Compare commits
2 Commits
ad437b517f
...
edc9fa50b6
Author | SHA1 | Date |
---|---|---|
sloum | edc9fa50b6 | |
sloum | 73d1829053 |
|
@ -194,6 +194,10 @@ The number stack can be manipulated in a number of ways. You have seem mathemati
|
|||
|
||||
`OVER` will copy the number underneath the top value on the stack and place the copy on the top of the stack without removing any numbers from the stack..
|
||||
|
||||
#### Ranges
|
||||
|
||||
_tally_ can accept ranges of cells for operation. However, _tally_ currently only supports summing the numerical values of those cells. The syntax is `A1:B3+`. The `+` at the end designates summing the range. Eventually there may be other range operations available. Locking rows and columns _can_ be used in ranges.
|
||||
|
||||
#### Errors
|
||||
|
||||
If there is a problem in your expression, the cell will report `#Err`, likely followed by a message about the nature of the problem. If you try to reference a stack value that doesn't exist, for example... or even a cell that does not exist.
|
||||
|
|
46
cell.go
46
cell.go
|
@ -128,7 +128,8 @@ func (c *cell) Calculate() {
|
|||
v = c.mask
|
||||
}
|
||||
} else if IsRange(v) {
|
||||
// TODO Apply range
|
||||
stackError = s.Sum(v)
|
||||
goto ERRCHECK
|
||||
}
|
||||
|
||||
switch true {
|
||||
|
@ -212,8 +213,9 @@ func (c *cell) Calculate() {
|
|||
}
|
||||
s.Push(v)
|
||||
}
|
||||
if stackError != nil {
|
||||
c.mask = "#Err: Stack underflow"
|
||||
|
||||
ERRCHECK: if stackError != nil {
|
||||
c.mask = fmt.Sprintf("#ERR: %s", stackError.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -414,3 +416,41 @@ func (s *stack) Ceil() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *stack) Sum(rng string) error {
|
||||
points := strings.Split(rng[:len(rng)-1], ":")
|
||||
pointA, _, _ := Addr2Point(points[0])
|
||||
pointB, _, _ := Addr2Point(points[1])
|
||||
rowStart := pointA.row
|
||||
rowEnd := pointB.row
|
||||
colStart := pointA.col
|
||||
colEnd := pointB.col
|
||||
if rowEnd < rowStart || colEnd < colStart {
|
||||
return fmt.Errorf("Range starts after range end")
|
||||
}
|
||||
if colEnd > wb.sheets[wb.sheet].cols-1 || rowEnd > wb.sheets[wb.sheet].rows-1 || colStart < 0 || rowStart < 0 {
|
||||
return fmt.Errorf("Range out of bounds")
|
||||
}
|
||||
|
||||
var sum float64 = 0.0
|
||||
var val float64
|
||||
var c cell
|
||||
var err error
|
||||
cells := wb.sheets[wb.sheet].cells
|
||||
|
||||
for row := rowStart; row <= rowEnd; row++ {
|
||||
for col := colStart; col <= colEnd; col++ {
|
||||
c = cells[row][col]
|
||||
val = c.num
|
||||
if c.kind == Expr {
|
||||
val, err = strconv.ParseFloat(c.mask, 64)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
sum += val
|
||||
}
|
||||
}
|
||||
s.Push(sum)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
10
main.go
10
main.go
|
@ -23,7 +23,7 @@ const (
|
|||
|
||||
var wb workbook
|
||||
var reAddr *regexp.Regexp = regexp.MustCompile(`^\$?[A-Z]\$?[0-9]+$`)
|
||||
var reAddrRange *regexp.Regexp = regexp.MustCompile(`^[A-Z][0-9]+:[A-Z][0-9]+$`)
|
||||
var reAddrRange *regexp.Regexp = regexp.MustCompile(`^\$?[A-Z]\$?[0-9]+:\$?[A-Z]\$?[0-9]+\+$`)
|
||||
var modified bool = false
|
||||
|
||||
type point struct {
|
||||
|
@ -152,9 +152,15 @@ func Addr2Point(addr string) (point, bool, bool) {
|
|||
return p, lockRow, lockCol
|
||||
}
|
||||
|
||||
func Point2Addr(p point) string {
|
||||
func Point2Addr(p point, lockRow, lockCol bool) string {
|
||||
var s strings.Builder
|
||||
if lockCol {
|
||||
s.WriteRune('$')
|
||||
}
|
||||
s.WriteRune(rune(p.col) + 65)
|
||||
if lockRow {
|
||||
s.WriteRune('$')
|
||||
}
|
||||
s.WriteString(strconv.Itoa(p.row+1))
|
||||
return s.String()
|
||||
}
|
||||
|
|
23
sheet.go
23
sheet.go
|
@ -141,8 +141,29 @@ func (s *sheet) PasteRelative() {
|
|||
if !lockCol {
|
||||
diffApply.col = refPoint.col-diff.col
|
||||
}
|
||||
p2a := Point2Addr(diffApply)
|
||||
p2a := Point2Addr(diffApply, lockRow, lockCol)
|
||||
c.expr[i] = p2a
|
||||
} else if IsRange(v) {
|
||||
op := v[len(v)-1]
|
||||
points := strings.Split(v[:len(v)-1], ":")
|
||||
startRefPoint, lockStartRow, lockStartCol := Addr2Point(points[0])
|
||||
endRefPoint, lockEndRow, lockEndCol := Addr2Point(points[1])
|
||||
diff := point{row: s.yankPoint.row-s.selection.row+1, col: s.yankPoint.col-s.selection.col+1}
|
||||
startApply := point{row: startRefPoint.row, col: startRefPoint.col}
|
||||
endApply := point{row: endRefPoint.row, col: endRefPoint.col}
|
||||
if !lockStartRow {
|
||||
startApply.row = startRefPoint.row-diff.row
|
||||
}
|
||||
if !lockStartCol {
|
||||
startApply.col = startRefPoint.col-diff.col
|
||||
}
|
||||
if !lockEndRow {
|
||||
endApply.row = endRefPoint.row-diff.row
|
||||
}
|
||||
if !lockEndCol {
|
||||
endApply.col = endRefPoint.col-diff.col
|
||||
}
|
||||
c.expr[i] = fmt.Sprintf("%s:%s%c", Point2Addr(startApply, lockStartRow, lockStartCol), Point2Addr(endApply, lockEndRow, lockEndCol), op)
|
||||
}
|
||||
}
|
||||
c.rawVal = strings.Join(c.expr, " ")
|
||||
|
|
10
tally.1
10
tally.1
|
@ -1,4 +1,4 @@
|
|||
.TH "tally" 1 "18 MAR 2021" "" "General Operation Manual"
|
||||
.TH "tally" 1 "20 MAR 2021" "" "General Operation Manual"
|
||||
.SH NAME
|
||||
\fBtally\fP- concatenative spreadsheet
|
||||
.SH SYNOPSIS
|
||||
|
@ -199,6 +199,14 @@ Remove the top value on the numerical stack and do nothing with it (throw it awa
|
|||
.B
|
||||
CLEAR
|
||||
Drop all values from the numerical stack. This would most often be used to ensure that no values will get flushed to the textual output buffer at the end of an expression. However, be wary of doing so as it likely indicates that some refactoring could prevent the need to use it in that way.
|
||||
.SH Range Operators
|
||||
The following is a list of the operators that \fBtally\fP recognizes as operating over a range of cells, as well as a description of what they do. Range operators take the form of \fI[start]:[end][oeprator]\fP, for example \fIA1:B3+\fP.
|
||||
.TP
|
||||
.B
|
||||
+
|
||||
Will sum all number values from the given range of cells. If a cell within the range is empty or of a textual type, or an expression that evaluates to empty or text, it will be treated as \fI0.0\fP for purposes of calculating the sum of the cells' values.
|
||||
.TP
|
||||
.B
|
||||
.SH BUGS
|
||||
There are very likely bugs. This software was largely made for personal use and is being made available so that others can modify it to their needs if they would like. Feel free to fork and patch as you see fit (within the terms of the Floodgap Free Software License).
|
||||
.SH LINKS
|
||||
|
|
Loading…
Reference in New Issue