goer@quads.uchicago.edu (Richard L. Goerwitz) (10/05/90)
I had to write this the other day, and it seemed to be something that
would be of general interest.
-Richard
############################################################################
#
# Name: slashbal.icn
#
# Title: Bal() with backslash escaping
#
# Author: Richard L. Goerwitz
#
# Version: 1.1
#
############################################################################
#
# I am often frustrated at bal()'s inability to deal elegantly with
# the common \backslash escaping convention (a way of telling Unix
# Bourne and C shells, for instance, not to interpret a given
# character as a "metacharacter"). I recognize that bal()'s generic
# behavior is a must, and so I wrote slashbal() to fill the gap.
#
# Slashbal behaves like bal, except that it ignores, for purposes of
# balancing, any character which is preceded by a backslash. Note
# that we are talking about internal backslashes, and not necessarily
# the backslashes used in Icon string literals. If you have "\(" in
# your source code, the string produced will have no backslash. To
# get this effect, you would need to write "\\(."
#
# BUGS: Note that, like bal() (v8), slashbal() cannot correctly
# handle cases where c2 and c3 intersect.
#
############################################################################
#
# Links: none
#
############################################################################
procedure slashbal(c1, c2, c3, s, i, j)
local allcs, chr, count
/c1 := &cset
/c2 := '('
/c3 := ')'
allcs := c1 ++ c2 ++ c3 ++ '\\'
/s := \&subject | stop("slashbal: No string argument.")
/i := \&pos | 1
/j := *s + 1
count := 0
s ? {
while tab(upto(allcs)) do {
chr := move(1)
if chr == "\\" then {
chr := move(1) | fail
if any(c1, chr) & count = 0 then
suspend .&pos - 1
}
else {
if any(c1, chr) & count = 0 then
suspend .&pos - 1
if any(c2, chr) then
count +:= 1
else if any(c3, chr) then
count -:= 1
}
}
}
end