# 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
