1. Introduction
SS is a batch spreadsheet processor for C programmers. It produces a spreadsheet display from plain text input files of commands, similar to the way documents are created using LaTeX. Although the resulting display is not directly interactive, one can interactively use commands to control formula evaluation and to select regions to display. It can be combined with a GUI front-end processor, such as the VECR/SS project, to enable easier interaction and graphics including plotting.SS includes all of the numeric operators from the C programming language, with the same syntax, precedence, and associativity as C. It also includes all of the functions from the C standard library math.h, as well as other numeric and range functions. It allows cycles and non-convergent iterative formulas, which are useful for certain applications.
2. Input and Output
SS first reads input from any files specified on the command line, then it reads standard input.SS processes input line-by-line. Multiple commands may appear on one line, separated by a semicolon.
Input lines may contain comments, which start with a '#' character and continue to the end of the line.
Input lines are joined together whenever one ends with a backslash followed by a literal newline character. In other words, the backslash and newline are removed, and the current line continues with the next line.
Output goes to standard output by default, but can be redirected globally using the output command, or redirected on a per-command basis using the plot and print commands. "stdout" and "-", with or without quotes, can be used as pseudo output file names to refer to standard output.
3. Cells - A0 Format
In A0 format, cells are specified by their column (one or two letters, A-Z, case-insensitive) and row (one-to-three digits 0-9), with an optional '$' preceding the column and/or row value to indicate that the cell is fixed.The column value represents an integer column number as follows:
column: letters A B C ... Z AA AB AC ... AZ BA BB BC ... BZ ... ZZ integer 0 1 2 ... 25 26 27 28 ... 51 52 53 54 ... 77 ... 701Example cell specifications:
a2 - relative $a2 - fixed column, relative row aa$31 - fixed row, relative column $b$100 - fixed row, fixed columnWhen copying formulas, relative cell references remain relative to the destination cells, and fixed references remain fixed.
Example:
b1 = 10*a1 + $d$0
copy b2:b5 b1:b4
print formulas
B
1 (10*A1)+$D$0
2 (10*A2)+$D$0
3 (10*A3)+$D$0
4 (10*A4)+$D$0
5 (10*A5)+$D$0
4. Cells - RC/CR Formats
In RC and CR formats, cell are specified by their row and column numbers, using the letters R and C (or r, c), with brackets around relative offsets.For example, relative to cell D2:
r0C0 - fixed row 0, fixed column 0 (same as C0R0 or A0) R1c2 - fixed row 1, fixed column 2 (same as C2R1 or C1) C[-2]R[] - relative column -2, same row, i.e. B2, relative to D2 R[-2]C[0] - relative row -2, same column, i.e. D0, relative to D2 R[1]C[+1] - relative row +1, relative column +1, i.e. E3, relative to D2 R[]C[] - relative row and column, no offsets, i.e. D2 relative to D2Use the format command to change the format used for printing formulas from A0 (the default) to RC or CR.
Example:
b1 = 10*a1 + $d$0
copy b2:b5 b1:b4
format RC; print formulas
1
1 (10*R[]C[-1])+R0C3
2 (10*R[]C[-1])+R0C3
3 (10*R[]C[-1])+R0C3
4 (10*R[]C[-1])+R0C3
5 (10*R[]C[-1])+R0C3
5. Ranges
A range consists of two cells, the start and end cells of the range, separated by a colon.
For example, A0:B9 (or A0:C1R9, or R0C0:R9C1, or C0R0:R9C1, etc.)
specifies a range including rows 0 to 9 of columns A and B.
The range start and end values do not have to be
in increasing order; B9:A0, B0:A9, and A9:B0 all refer to the same group of
cells as A0:B9, but correspond to different directions for traversing the
range. For example the command copy a0:a9 b9:b0 would copy column b to a
in reverse order.
By default, ranges are traversed byrows to improve cache performance, since elements in a row are adjacent in memory. That is, in pseudo-code:
for row = start_row to end_row
for col = start_col to end_col
use cell[row,col]
The bycols option can be used with the
copy, eval, fill, and plot commands
to cause evaluation by columns.
That is, in pseudo-code:
for col = start_col to end_col
for row = start_row to end_row
use cell[row,col]
Note that the starting row may be less than, equal to, or greater than the
ending row. Same for columns. So a range may consist of a single cell,
row, or column (a0:a0, a0:d0, a0:a4), cells in "increasing" order (a0:b4), or
cells in "partial decreasing" order (a4:b0, b0:a4), or cells in "decreasing"
order (b4:a0).
A range basically represents a list of cells, and is explicitly converted to a list when used in a range assignment or numeric function argument.
A range consisting of a single cell may be specified using just that one cell, e.g. A0 as a range is the same as A0:A0.
6. Primitive Data Types
The SS primitive data types are:
- double precision floating point
- All numeric calculations are performed and stored using
double precision floating point.
The cast operators, (int) and (long), can be used to truncate an expression to integral form, and the resulting integer will be stored using double precision floating point. Also, ceil, floor, modf, and round are numeric functions involving integral forms.
- string
- A string is a sequence of characters enclosed in 'single' or "double" quotes.
No escape sequences are recognized.
If a string appears in a numeric calculation it is treated as having the value 0.0
- constant
- The built-in constants are:
HUGE_VAL = Inf RAND_MAX = 32767 pi = 3.14159
The values of the constants shown are from a Solaris/sparc system and may vary depending on the system. To check the values of the constants use command help or print constants.
7. Macros
A macro is defined using a @define command:@define macname macvalue...where, at the beginning of a line there may be optional leading whitespace, then the literal string "@define", then whitespace, then a macro name which starts with a letter followed by zero or more letters or digits, then whitespace, then the macro value up to the end of the line.
Macro references of the form @macname are then expanded to the macro value.
Naturally, a macro can refer to other macros, and a macro must be defined before it can be expanded.
Example:
% cat macros.ss # test macros @define pf1 @pets AND @food @define pets dog OR cat @define food fish OR pie @define pf2 (@pets) AND (@food) y1 = @pf1 AND ate y2 = ate AND @pf2 % echo "print macros formulas" | ss macros.ss
@pf2 -> (@pets) AND (@food) @food -> fish OR pie @pets -> dog OR cat @pf1 -> @pets AND @food Y 1 (dog||(cat&&fish))||(pie&&ate) 2 (ate&&(dog||cat))&&(fish||pie)
8. Symbols
User-defined variables are stored in a symbol table and evaluated each time the spreadsheet is evaluated. Note that cell names can not be used as variables.Example:
% cat syms.ss a = 29 d2r = d*pi/180 a0 = pi ca = a0 b0 = ca eval 4; print symbols formulas values % ss < syms.ss
ss_eval: converged after 3 iterations a = 29 d2r = (d*pi)/180 = 0 d = 0 ca = A0 = 3.14159 A B 0 pi ca A B 0 3.14 3.14
9. Operators
SS operators have the same precedence, associativity, and meaning as those in the C programming language.SS also includes operators ** for exponentiation, ^^ for logical XOR, and the logical assignment operators &&=, ^^=, and ||=. The keywords NOT, AND, XOR, and OR, case-insensitive, may also be used to represent the logical operators.
SS does not include the C array, structure, and pointer operators.
The operators are:
() parentheses, (expr) ++ postfix increment, x++ -- postfix decrement, x-- ++ prefix increment, ++x -- prefix decrement, --x - unary minus + unary plus ~ bitwise NOT ! logical NOT & address of cell or symbol (int) cast (long) cast ** exponentiation, x**y == pow(x,y) * multiplication / division % mod, x%y == fmod(x,y) + addition - subtraction << shift left, x<<y == x*2**y >> shift right, x>>y == x/2**y < less than <= less than or equal > greater than >= greater than or equal == equal != not equal & bitwise AND ^ bitwise XOR | bitwise OR && logical AND ^^ logical XOR || logical OR ?: conditional operator, e1 ? e2 : e3 = assignment *= multiplication assignment /= division assignment %= mod assignment += addition assignment -= subtraction assignment <<= shift left assignment >>= shift right assignment &= bitwise AND assignment ^= bitwise XOR assignment |= bitwise OR assignment &&= logical AND assignment ^^= logical XOR assignment ||= logical OR assignment , comma operatorThe bit shift operators <<, <<=, >>, and >>= are implemented for floating-point using ldexp() to adjust the binary exponent by the specified power of 2. For the other bitwise operators, the floating-point operands are converted to long integers to perform the operations.
10. Numeric Functions
SS includes all of the functions from the standard C math library, and more.Most of the numeric functions take one expression argument and return one value.
A few of the functions take no arguments (drand, rand, time), and some take two arguments (atan2, fmod, frexp, ldexp, modf, pow).
The numeric functions are:
acos arc cosine asin arc sine atan two-quadrant arctangent atan2 four-quadrant arctangent, atan2(y,x) ~= atan(y/x) ceil ceiling cos cosine cosh hyperbolic cosine drand pseudo-random double, 0.0 <= drand() < 1.0 exp exponential fabs absolute value floor floor fmod mod, x%y == fmod(x,y) frexp extract fraction and exponent, frac = frexp(x, &expo) irand pseudo-random integer, 0 <= irand(i) <= i-1 isprime check primeness of small numbers ldexp ldexp(x,e) produces x * (2**e) log natural logarithm log10 base 10 logarithm modf extract fraction and integral parts, frac = modf(x, &int) nrand pseudo-random normal (Gaussian) -6.0 <= nrand() < 6.0 pow exponentiation, x**y == pow(x,y) rand pseudo-random integer, 0 <= rand() <= RAND_MAX round round to nearest integral value sin sine sinh hyperbolic sine sqrt square root tan tangent tanh hyperbolic tangent time time in seconds since 00:00:00 UTC, January 1, 1970Notes:
For frexp and modf, the second argument must be the address of a cell or symbol, since it will be assigned one of the result values.
The pseudo-random number generator functions are initialized using
srand(time()) when the program is run, but you can
reinitialize using the srand command.
isprime uses an inefficient brute-force method, checking for divisibility by all possible divisors. It should only be used to check for primeness of relatively small numbers.
11. Range Functions
Range functions take an argument list of expressions and ranges and return one value.The range functions are:
avg average of the defined cells count number of cells defined majority non-zero if majority of defined cells are non-zero max maximum of the defined cells min minimum of the defined cells prod product of the defined cells stdev standard deviation of the defined cells sum sum of the defined cells
12. Commands
SS commands are:byrows|bycols - set default direction copy [byrows|bycols] dest_range src_range debug [on|off] eval [byrows|bycols] [range|symbols] [number_of_iterations] exit fill [byrows|bycols] range start_expr, increment_expr format A0|RC|CR - formula printing format format [cell|row|col|range|symbols] "fmt_string" help - print list of operators, functions, commands and constants ttfill [byrows|bycols] range load "fname"... output "fname" plot|plot2d|plot3d ["fname"] [byrows|bycols] [range] print ["fname"] [byrows|bycols] [range] [all|... ...macros|symbols|formulas|values| formats|pointers|constants|functions]... quit srand expr - initialize the pseudo-random number generatorAdditional information:
- eval
-
If no range or symbols option is specified,
eval evaluates the spreadsheet for the number of iterations specified
(default is 2 iterations). Each iteration of evaluation first
evaluates the symbol table, then evaluates the cells twice: first
starting at the top-left corner of the cells being used and traversing
the range to the bottom-right corner of the cells being used; then
again starting at the bottom-right corner and traversing to the
top-left corner.
If the symbols option is specified, only the symbol table is evaluated for the number of iterations specified (default is 2 iterations).
If a range is specified, only the symbol table and that range are evaluated for the number of iterations specified (default is 2 iterations).
- fill
- Fill a range with constant values, starting with the start expression value,
and increasing by the increment expression value for subsequent cells.
The start and increment expressions are evaluated only once,
before filling starts.
- ttfill
- Fill a range with constant 0,1 values suitable as inputs for a truth-table.
For example, ttfill a0:c7 produces 8 rows and 3 columns representing
the 8 possible 3-bit values:
A B C 0 0 0 0 1 0 0 1 2 0 1 0 3 0 1 1 4 1 0 0 5 1 0 1 6 1 1 0 7 1 1 1 - format
- The format A0, RC, and CR options
specify the format used for printing formulas.
For printing spreadsheet values, the format can be set globally or for a specific cell, row, column or range. The default global format is "%.2f". If a cell is not assigned a format, printing will use the cell's row format, if set; otherwise it will use the cell's column format, if set; otherwise it will use the global format.
The default format for printing symbol table values is "%g". This can be changed using the format symbols command.
- plot|plot2d|plot3d
- The plot commands do not actually plot anything, they simply display output in a form suitable for input to another program like a plot utility.
13. Example
% cat grades.ss a0:d0 = { "grade", "score", "avg", "stdev"} mean = avg(b1:b5); c1 = mean; d1 = stdev(b1:b5) a1 = 80+15*(b1-mean)/$d$1 copy a2:a5 a1:a4 b1:b5 = { 57, 67, 92, 87, 76 } eval print symbols values formulas pointers % ss < grades.ss
mean = avg(B1:B5) = 75.8 A B C D 0 grade score avg stdev 1 60.29 57.00 75.80 14.31 2 70.77 67.00 3 96.98 92.00 4 91.74 87.00 5 80.21 76.00 A B C D 0 "grade" "score" "avg" "stdev" 1 80+((15*(B1-mean))/$D$1) 57 mean stdev(B1:B5) 2 80+((15*(B2-mean))/$D$1) 67 3 80+((15*(B3-mean))/$D$1) 92 4 80+((15*(B4-mean))/$D$1) 87 5 80+((15*(B5-mean))/$D$1) 76 A B C D 0 1051f58 1052598 10525d0 1052608 1 10529f8 0 1052720 10527c8 2 10529f8 0 3 10529f8 0 4 10529f8 0 5 10529f8 0
14. Keywords and Names
Keywords are reserved words and can not be used as variable names.NOT, AND, XOR, and OR are the only case-insensitive keywords.
The names of the numeric and range functions as well as the names of the commands are all keywords.
stdout, byrows, bycols and the print options all, constants, formats, formulas, functions, macros, pointers, symbols, values are all keywords.
The formula printing formats A0, RC, CR and the debug options on, off are not keywords. A0 is a valid cell reference; RC, CR, and on are valid column names. Column names and off can be used as variable names.
15. Cycles and Convergence
If a cell depends on itself, that forms a cycle and the spreadsheet may not converge when evaluated.Cycles which converge can be used to implement iterative algorithms. For example, the following spreadsheet uses Newton's method to find the square root of x:
% cat sqrt.ss x = 2 a0 = b0 ? b0 : x/2 b0 = (a0+x/a0)/2 format "%20.18g"Since a0 depends on b0, and b0 depends on a0, there is a cycle.
a0 will be set to b0 if b0 is non-zero, otherwise a0 will be set to x/2 to initialize the algorithm. So a0 represents the previous value of b0, and b0 represents the next estimate of the square root. Newton's method converges quickly:
% echo "print all; eval a0:b0 10; print values" | ss sqrt.ss
x = 2 A B 0 B0 ? B0 : ((x/2)) (A0+(x/A0))/2 A B 0 0 0 ss_eval_range: converged after 7 iterations A B 0 1.41421356237309492 1.41421356237309492
Finite element analysis is another application which requires iteration and can be set up in a spreadsheet. In the following small example, the value of each non-boundary cell is computed as the average of the cell's four nearest neighbors.
% cat cycles.ss # average of 4 nearest neighbors # R1C1 = (R[]C[-1] + R[]C[+1] + R[-1]C[] + R[+1]C[])/4 # copy r1c2:r1c5 r1c1:r1c4 # set up one row copy r2c1:r5c5 r1c1:r4c5 # copy to rows 2..5 # fill r0c0:r0c6 1, 0 # boundary conditions, fill r1c0:r6c0 1, 0 # 1's top and left fill r1c6:r6c6 0, 0 # 0's right and bottom fill r6c1:r6c5 0, 0 # format "%6.4f"; format RC # print values; eval; eval 1000; print values % ss < cycles.ss
0 1 2 3 4 5 6 0 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 2 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 3 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 4 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 5 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 6 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 ss_eval: still changing after 2 iterations ss_eval: converged after 74 iterations 0 1 2 3 4 5 6 0 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1 1.0000 0.9374 0.8747 0.8040 0.7010 0.5000 0.0000 2 1.0000 0.8747 0.7576 0.6404 0.5000 0.2990 0.0000 3 1.0000 0.8040 0.6404 0.5000 0.3596 0.1960 0.0000 4 1.0000 0.7010 0.5000 0.3596 0.2424 0.1253 0.0000 5 1.0000 0.5000 0.2990 0.1960 0.1253 0.0626 0.0000 6 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000The spreadsheet may not converge when using operators ++, --, +=, *=, etc. and the rand, irand, or drand pseudo-random number generator functions, since they produce varying values on each evaluation. However, these operators and functions are still useful, in particular for Monte-Carlo simulations.
The following simple example generates pseudo-random values for a0, with b0 representing the sum, c0 the evaluation count, and d0 the average:
% cat rand.ss a0 = drand() b0 += a0 d0 = b0/++c0 eval a0:d0 10; print values % ss < rand.ss
ss_eval_range: still changing after 10 iterations A B C D 0 0.44 5.12 10.00 0.51
16. Debugging
Debugging of the flex scanner and bison parser is enabled by specifying-d as the first command-line argument.
Additional debugging of internal operations is enabled using the debug command, which toggles debug mode or explicitly turns it on or off.
To obtain a list of the internal functions which implement all
of the operators as well as numeric and range functions, use command:
print functions