sed in (pseudo) microcode, by Carlos J. Duarte.
[ This article was posted to the seders mailing list ]



Al, this is a little doc, with some pseudo code, of
a sed implementation.

The idea, is when people (that knows sed), has a question
or need some fine tunning, to quickly answered themselves.

One particulary example, are the strange behaviors of D, and a\
(well, sort of). 

As a last note remark, I am revieing my scripts packages, and
also some documentation on sed (do-it-with-sed, advanced-sed,
hints-sed? or sed-fine-tunning). This should be ok on august. 
For now (upto end of july), I will not (probably), dedicate
any time to that.

So, there goes the text.

ADDRESSES
=========

(0) no address, just the command per se
(1) a single address or none, is permitted
(2) a single address, a double address, or none is permitted

any address, if specified, may be a number -- specifies
the input line number, or a regular expression -- specifies
all pattern spaces, that matches it.

one address, appears per se, before the command
two addresses, appears separated per a comma `,'

if an address is omitted, the command will be apllied
on all pattern spaces that passes through it

y/a/b/                  executes on all ps
3 y/a/b/                executes on ps which last line loaded, was 3
/foo/ y/a/b/            executes on ps that matches /foo/
4,/foo/ y/a/b/          executes from ps which last line loaded was 4,
                        up to, including, ps that matches /foo/
/foo/,5 y/a/b/          as above, but from /foo/ up to 5

COMMANDS MICROCODE
==================

notes:
- first, everything begins with a (sic) `goto [end]', after
  all variables have been zeroed/offed/emptyed

- all commands, have a `pop ps' and a `push ps', to enforce that
  they really operate on patern space

- the `print ps to stdout' "microcode" below, prints an extra newline
  after the print the `ps' itself

        [end]
        . pop ps
        . if not nflag and line_counter>=1, print ps to stdout
        . print append_buffer to stdout (which might be empty)
        . empty append_buffer
        . set tflag off (see s, t)
        . if come_from_D
        .       set come_from_D off (see D)
        . else
        .       if no more input lines, exit
        .       load next line into ps, increment line_counter
        . push ps
        . goto start

(2) s/RE/replacement/[gp#w], #: 1-9
        . pop ps
        . if # not given, or g given, #=1
        . set last_match = begin of ps
        !! do not set tflag off (see t, [end])
        [1]
        . repeat # searches for RE, on ps, from last_match to end
        . if found
        .       tflag on
        .       replace the found match, per `replacement'
        .       if w file, append ps at end of `file'
        .       if p, print ps to stdout
        .       if g, set last_match to end of replacement+1 and goto [1]
        . push ps

(2) y/list1/list2/
        . pop ps
        . foreach character c1 on list1
        .       fetch character c2 from list2
        .       replace all occurrences of c1 per c2
        . push ps
(1)i\
text
        . print text to stdout immediatly

(1)a\
text
        . collect (i.e append) text to append_buffer (see [end])

(2)c\
text
        . print text to stdout immediatly
        . pop ps
        . empty ps
        . push ps
        . goto [end]
        !! because ps is empty, the `print ps' at [end] will not
           produce output

(1)r file
        . print contents of file, immediatly to stdout

(2)w file
        . pop ps
        . append ps at end of file
        . push ps

(0): label
        . name next command, as `label'

(2)b label
        . goto command named `label'

(2)t label
        . if tflag on (see s///)
        .       set tflag off
        .       goto command `label'

(1)q
        . pop ps
        . if not nflag, print ps to stdout
        . print append_buffer (might be empty, which cause no output)
        . exit

(2)p
        . pop ps
        . print ps to stdout
        . push ps

(2)l
        . pop ps
        . copy ps to tmp
        . replace on tmp, some special characters, per their
          conventional equivalents \x
        . print tmp
        . push ps

(1)=
        . print line_counter to stdout

(2)n
        . if no more lines on input, goto [end]
        . pop ps
        . if not nflag, print ps to stdout
        . load next line into ps, increment line_counter
        . push ps
        !! and continues, does not jump to start, or end

(2)d
        . pop ps
        . empty ps
        . push ps
        . goto [end]

(2)h
        . pop ps
        . set hold_buffer as ps
        . push ps

(2)H
        . pop ps
        . set hold_buffer to hold_buffer+\n+ps
        . push ps

(2)g
        . pop ps
        . set ps as hold_buffer
        . push ps

(2)G
        . pop ps
        . set ps as ps+\n+hold_buffer
        . push ps

(2)x
        . pop ps
        . push hold_buffer
        . set hold_buffer as ps
        !! exchange hold buffer with pattern space

(2)N
        . if no more lines on input, goto [end]
        . pop ps
        . load next line into tmp, increment line_counter
        . set ps to ps+\n+tmp
        . push ps
        !! and continues, does not jump to start, or end

(2)P
        . pop ps
        . copy ps to tmp
        . print remove from first \n upto end
        . print ps to stdout
        . push tmp

(2)D
        . pop ps
        . if ps does not contain a \n
        .       empty ps
        .       push ps
        .       goto [end]
        !! i.e. does the same as `d'
        . remove from beginning of ps, upto, including, first \n
        . push ps
        . set come_from_D on (see [end])
        . goto [end]
        !! do not load next line, if ps contained \n

==
Carlos Duarte, 980712