# bre2ere.sed - convert BRE to ERE sed
#
# note: ^ and $ not at start of end resp. of the RE are considered as
# literal chars.
# (POSIX documents as an option /\(^a$\)/ to be equivalent to /^\(a\)$/,
# here it gets converted to /(\^a\$)/)

s/'/'a/g
s/_/'b/g

# parse the line
s/^/_/

s/_\([  ]*\)/\1_/
# look for optional addresses before the command
:addr
# a 's' in the hold buffer indicates that the RE was part of a subst
# command. Since we're looking for addresses, clear the hold buffer.
x  
s/.*//
x  
# skip <address>, <address><comma>, <address>!,
s/_\([0-9!,$  ]*\)/\1_/

# handle /re/ as if it was \/re/ (i.e. special case of \xrex)
/_\// {
    s//\/_\//
    b rebeg
}  

# handle \xrex
/_\\'*./ {
    # we will carry the delimiter after the _
    s/_\\\('*.\)/\\\1_\1/
    :rebeg
    # first case: ^ as first position
    s/\(_'*.\)^/^\1/
    :reloop
    /_\('*.\)\1/ b reend
    # skip one ordinary char
    s/\(_'*.\)\([^'/[\(){}+?|^]\)/\2\1/
    # ( -> \(
    s/\(_'*.\)\([(){}?+|^]\)/\\\2\1/
    # \( -> (
    s/\(_'*.\)\\\([(){}]\)/\2\1/
    # $ -> \$ except if last
    s/_\('*.\)$\1/$_\1\1/
    s/\(_'*.\)\$/\\$\1/
    # skip any other \x
    s/\(_'*.\)\([\']'*[^(){}]\)/\2\1/
    # skip bracket expression
    s/\(_'*.\)\(\[\^'*.[^]]*]\)/\2\1/
    s/\(_'*.\)\(\['*.[^]]*]\)/\2\1/
    # loop
    b reloop
    :reend
    # if an s is in the hold buf, go back to s
    x
    /s/ b subst
    x
    s/_\('*.\)\1/\1_/
}  

# skip white space and any !
s/_\([!  ]*\)/\1_/

# if a comma is found, loop for the second address
/_,/ b addr

# we now reach the command char
/_s'*./ {
    s/_s\('*.\)/s\1_\1/
    x
    s/^/s/
    x
    b rebeg
    :subst
    x
    s/_\('*.\)\1/\1_\1/
    :rhsloop
    /_\('*.\)\1/ b rhsend
    s/\(_'*.\)\([^\']\)/\2\1/
    s/\(_'*.\)\([\']'*.\)/\2\1/
    /_'*.\\$/ {
        s/_\('*.\)\\$/\\\1/
        s/'b/_/g
        s/'a/'/g
        N
        s/'/'a/g
        s/_/'b/g
        s/\\\('*.\)\(\n\)/\\\2_\1/
    }
    b rhsloop
    :rhsend
    s/_\('*.\)./\1_/
    # flags
    s/_\([0-9pg]*\)/\1_/
    # w flag handled as the w command
}  

/_y'*./ {
    s/_y\('*.\)/y\1_\1/
    :y1loop
    /_\('*.\)\1/ {
        s/_\('*.\)\1/\1_\1/
        b y2loop
    }
    s/\(_'*.\)\([^\]\)/\2\1/
    s/\(_'*.\)\([\']'*.\)/\2\1/
    b y1loop
    :y2loop
    /_\('*.\)\1/ b y2end
    s/\(_'*.\)\([^\]\)/\2\1/
    s/\(_'*.\)\([\']'*.\)/\2\1/
    b y2loop
    :y2end
    s/_\('*.\)\1/\1_/
}  

# :label, b label, t label, r file, w file (cmd & flag), # comment
# all these include the end of line
/_\([bt:rw#]\)/ b out

# simple commands
s/_\([dDgGhHlnNpPqx}]\)/\1_/

# a\, c\, i\
/_\([aic]\)/ {
    s//\1_/
    :aloop
    s/_\([^\]*\)/\1_/
    /_\\$/ {
        s//\\/
        s/'b/_/g
        s/'a/'/g
        N
        s/'/'a/g
        s/_/'b/g
        s/\(\n\)/\1_/
    }
    s/_\(\\:*.\)/\1_/
    /_$/ !b aloop
    b out
}  

# skip whitespace
s/_\([  ]*\)/\1_/

# loop while there is still a command
/_[;{]/ {
    s/_\([;{]\)/\1_/
    b addr
}  

/_$/ b out

# weird case
h  
s/[^_]*_/unknown construct: /
p  
i\
line was:
x  
q  

:out
# remove the _
s/_//
# unquote _ and '
s/'b/_/g
s/'a/'/g

### colorized by sedsed, a debugger and code formatter for sed scripts
### original script: http://sed.sf.net/local/scripts/bre2ere.sed