Compare commits

...

2 Commits

Author SHA1 Message Date
sloum edc9fa50b6 Fixes locking for relative reference and adds range relative reference 2021-03-20 15:08:07 -07:00
sloum 73d1829053 Adds ranges and sum operator 2021-03-20 14:54:06 -07:00
5 changed files with 86 additions and 7 deletions

View File

@ -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
View File

@ -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
View File

@ -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()
}

View File

@ -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
View File

@ -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