+(defun org-table-expand-lhs-ranges (equations)
+ "Expand list of formulas.
+If some of the RHS in the formulas are ranges or a row reference, expand
+them to individual field equations for each field."
+ (let (e res lhs rhs range r1 r2 c1 c2)
+ (while (setq e (pop equations))
+ (setq lhs (car e) rhs (cdr e))
+ (cond
+ ((string-match "^@-?[-+I0-9]+\\$-?[0-9]+$" lhs)
+ ;; This just refers to one fixed field
+ (push e res))
+ ((string-match "^[a-zA-Z][_a-zA-Z0-9]*$" lhs)
+ ;; This just refers to one fixed named field
+ (push e res))
+ ((string-match "^@[0-9]+$" lhs)
+ (loop for ic from 1 to org-table-current-ncol do
+ (push (cons (format "%s$%d" lhs ic) rhs) res)
+ (put-text-property 0 (length (caar res))
+ :orig-eqn e (caar res))))
+ (t
+ (setq range (org-table-get-range lhs org-table-current-begin-pos
+ 1 nil 'corners))
+ (setq r1 (nth 0 range) c1 (nth 1 range)
+ r2 (nth 2 range) c2 (nth 3 range))
+ (setq r1 (org-table-line-to-dline r1))
+ (setq r2 (org-table-line-to-dline r2 'above))
+ (loop for ir from r1 to r2 do
+ (loop for ic from c1 to c2 do
+ (push (cons (format "@%d$%d" ir ic) rhs) res)
+ (put-text-property 0 (length (caar res))
+ :orig-eqn e (caar res)))))))
+ (nreverse res)))
+
+(defun org-table-formula-handle-first/last-rc (s)
+ "Replace @<, @>, $<, $> with first/last row/column of the table.
+So @< and $< will always be replaced with @1 and $1, respectively.
+The advantage of these special markers are that structure editing of
+the table will not change them, while @1 and $1 will be modified
+when a line/row is swapped out of that privileged position. So for
+formulas that use a range of rows or columns, it may often be better
+to anchor the formula with \"I\" row markers, or to offset from the
+borders of the table using the @< @> $< $> makers."
+ (let (n nmax len char (start 0))
+ (while (string-match "\\([@$]\\)\\(<+\\|>+\\)\\|\\(remote([^\)]+)\\)"
+ s start)
+ (if (match-end 3)
+ (setq start (match-end 3))
+ (setq nmax (if (equal (match-string 1 s) "@")
+ (1- (length org-table-dlines))
+ org-table-current-ncol)
+ len (- (match-end 2) (match-beginning 2))
+ char (string-to-char (match-string 2 s))
+ n (if (= char ?<)
+ len
+ (- nmax len -1)))
+ (if (or (< n 1) (> n nmax))
+ (error "Reference \"%s\" in expression \"%s\" points outside table"
+ (match-string 0 s) s))
+ (setq start (match-beginning 0))
+ (setq s (replace-match (format "%s%d" (match-string 1 s) n) t t s)))))
+ s)
+