]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Change mkopcodeh.awk into tool/mkopcodeh.tcl.
authordrh <drh@noemail.net>
Wed, 7 Oct 2015 02:52:09 +0000 (02:52 +0000)
committerdrh <drh@noemail.net>
Wed, 7 Oct 2015 02:52:09 +0000 (02:52 +0000)
FossilOrigin-Name: ed0ebc460b54939862e3bddee2bb9bcb9f69c747

Makefile.in
Makefile.msc
main.mk
manifest
manifest.uuid
mkopcodeh.awk [deleted file]
tool/mkopcodeh.tcl [new file with mode: 0644]

index 5c78abde946428b2d35a37bc3d9fa38bff323208..20c8420d34bf74980d1f68c51c6bb02dab4c209d 100644 (file)
@@ -902,8 +902,8 @@ tclsqlite3$(TEXE):  tclsqlite-shell.lo libsqlite3.la
 opcodes.c:     opcodes.h $(TOP)/mkopcodec.awk
        $(NAWK) -f $(TOP)/mkopcodec.awk opcodes.h >opcodes.c
 
-opcodes.h:     parse.h $(TOP)/src/vdbe.c $(TOP)/mkopcodeh.awk
-       cat parse.h $(TOP)/src/vdbe.c | $(NAWK) -f $(TOP)/mkopcodeh.awk >opcodes.h
+opcodes.h:     parse.h $(TOP)/src/vdbe.c $(TOP)/tool/mkopcodeh.tcl
+       cat parse.h $(TOP)/src/vdbe.c | $(TCLSH_CMD) $(TOP)/tool/mkopcodeh.tcl >opcodes.h
 
 # Rules to build parse.c and parse.h - the outputs of lemon.
 #
index 678b547fed565a19432fd30a9e73d7317bd76506..124761757d178dc7f59ed5e103baeef97b0981f0 100644 (file)
@@ -1575,8 +1575,8 @@ tclsqlite3.exe:   tclsqlite-shell.lo $(SQLITE3C) $(LIBRESOBJS)
 opcodes.c:     opcodes.h $(TOP)\mkopcodec.awk
        $(NAWK) -f $(TOP)\mkopcodec.awk opcodes.h > opcodes.c
 
-opcodes.h:     parse.h $(TOP)\src\vdbe.c $(TOP)\mkopcodeh.awk
-       type parse.h $(TOP)\src\vdbe.c | $(NAWK) -f $(TOP)\mkopcodeh.awk > opcodes.h
+opcodes.h:     parse.h $(TOP)\src\vdbe.c $(TOP)\tool\mkopcodeh.tcl
+       type parse.h $(TOP)\src\vdbe.c | $(TCLSH_CMD) $(TOP)\tool\mkopcodeh.awk > opcodes.h
 
 # Rules to build parse.c and parse.h - the outputs of lemon.
 #
diff --git a/main.mk b/main.mk
index cded12e5a3655da0b2060699eb7a8ee6d4d81cc0..cc413faca25c027207769465281e316c4ab70270 100644 (file)
--- a/main.mk
+++ b/main.mk
@@ -582,9 +582,9 @@ tclsqlite.o:        $(TOP)/src/tclsqlite.c $(HDR)
 opcodes.c:     opcodes.h $(TOP)/mkopcodec.awk
        $(NAWK) -f $(TOP)/mkopcodec.awk opcodes.h >opcodes.c
 
-opcodes.h:     parse.h $(TOP)/src/vdbe.c $(TOP)/mkopcodeh.awk
+opcodes.h:     parse.h $(TOP)/src/vdbe.c $(TOP)/tool/mkopcodeh.tcl
        cat parse.h $(TOP)/src/vdbe.c | \
-               $(NAWK) -f $(TOP)/mkopcodeh.awk >opcodes.h
+               tclsh $(TOP)/tool/mkopcodeh.tcl >opcodes.h
 
 # Rules to build parse.c and parse.h - the outputs of lemon.
 #
index 662c7dfb6d5e708e401a11e834183ad83b6ebd20..1a4dd940953662895b6c95067a566a8ee896a878 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,9 +1,9 @@
-C Remove\sthree\sobsolete\sand\sunused\sfiles\sfrom\stool/
-D 2015-10-07T00:35:18.445
+C Change\smkopcodeh.awk\sinto\stool/mkopcodeh.tcl.
+D 2015-10-07T02:52:09.315
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
-F Makefile.in 2143eeef6d0cc26006ae5fc4bb242a4a8b973412
+F Makefile.in dd1f363468240142a5be1c9d58014dc9b8eae2f4
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
-F Makefile.msc b9054642ab305be4174d8b0433c9951c2839701d
+F Makefile.msc 8fb99d7b4e8b2e812a2360b8356d956d26e0e953
 F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858
 F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7
 F VERSION ccfc4d1576dbfdeece0a4372a2e6a2e37d3e7975
@@ -263,9 +263,8 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e
 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk 151fcaba704fdeeb0a1941857ef6e1d6216732d8
+F main.mk 9fe51a296a2550282db357d2b3825cc32fbc455b
 F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
-F mkopcodeh.awk 0e7f04a8eb90f92259e47d80110e4e98d7ce337a
 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
 F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -1352,6 +1351,7 @@ F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
 F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6
 F tool/mkautoconfamal.sh d1a2da0e15b2ed33d60af35c7e9d483f13a8eb9f
 F tool/mkkeywordhash.c dfff09dbbfaf950e89af294f48f902181b144670
+F tool/mkopcodeh.tcl e04177031532b7aa9379ded50e820231ac4abd6e
 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
 F tool/mkpragmatab.tcl 84af2b180484323a2ea22a2279e8bd9e3e1e492e
 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
@@ -1389,7 +1389,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P a05f903c64edeba8a9748aad68f5981943e68b3c
-R d4529eb5d734c0707e0a910200ff6fc6
+P 0abd65294e6e8db68e7ce6724f02f17ba1cb3422
+R 33730b016d975e72f95dcd99735ce552
+T *branch * omit-awk
+T *sym-omit-awk *
+T -sym-trunk *
 U drh
-Z 8d61b7e9a6e9a2f3b2856a04c9b6debc
+Z 05cb2395dd6fc47d133085b2716a644b
index c3e287c668f6500f29e0247952db2b75bbc53720..7bf1ca41d861c54dcc262b443270898e1cda2f8e 100644 (file)
@@ -1 +1 @@
-0abd65294e6e8db68e7ce6724f02f17ba1cb3422
\ No newline at end of file
+ed0ebc460b54939862e3bddee2bb9bcb9f69c747
\ No newline at end of file
diff --git a/mkopcodeh.awk b/mkopcodeh.awk
deleted file mode 100644 (file)
index 474ae4f..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-#!/usr/bin/awk -f
-#
-# Generate the file opcodes.h.
-#
-# This AWK script scans a concatenation of the parse.h output file from the
-# parser and the vdbe.c source file in order to generate the opcodes numbers
-# for all opcodes.  
-#
-# The lines of the vdbe.c that we are interested in are of the form:
-#
-#       case OP_aaaa:      /* same as TK_bbbbb */
-#
-# The TK_ comment is optional.  If it is present, then the value assigned to
-# the OP_ is the same as the TK_ value.  If missing, the OP_ value is assigned
-# a small integer that is different from every other OP_ value.
-#
-# We go to the trouble of making some OP_ values the same as TK_ values
-# as an optimization.  During parsing, things like expression operators
-# are coded with TK_ values such as TK_ADD, TK_DIVIDE, and so forth.  Later
-# during code generation, we need to generate corresponding opcodes like
-# OP_Add and OP_Divide.  By making TK_ADD==OP_Add and TK_DIVIDE==OP_Divide,
-# code to translate from one to the other is avoided.  This makes the
-# code generator run (infinitesimally) faster and more importantly it makes
-# the library footprint smaller.
-#
-# This script also scans for lines of the form:
-#
-#       case OP_aaaa:       /* jump, in1, in2, in3, out2-prerelease, out3 */
-#
-# When such comments are found on an opcode, it means that certain
-# properties apply to that opcode.  Set corresponding flags using the
-# OPFLG_INITIALIZER macro.
-#
-
-
-# Remember the TK_ values from the parse.h file
-/^#define TK_/ {
-  tk[$2] = 0+$3    # tk[x] holds the numeric value for TK symbol X
-}
-
-# Find "/* Opcode: " lines in the vdbe.c file.  Each one introduces
-# a new opcode.  Remember which parameters are used.
-/^.. Opcode: / {
-  currentOp = "OP_" $3
-  m = 0
-  for(i=4; i<=NF; i++){
-    x = $i
-    if( x=="P1" ) m += 1
-    if( x=="P2" ) m += 2
-    if( x=="P3" ) m += 4
-    if( x=="P4" ) m += 8
-    if( x=="P5" ) m += 16
-  }
-  paramused[currentOp] = m
-}
-
-# Find "** Synopsis: " lines that follow Opcode:
-/^.. Synopsis: / {
-  if( currentOp ){
-    x = $3
-    for(i=4; i<=NF; i++){
-      x = x " " $i
-    }
-    synopsis[currentOp] = x
-  }
-}
-
-# Scan for "case OP_aaaa:" lines in the vdbe.c file
-/^case OP_/ {
-  name = $2
-  sub(/:/,"",name)
-  sub("\r","",name)
-  op[name] = -1       # op[x] holds the numeric value for OP symbol x
-  jump[name] = 0
-  in1[name] = 0
-  in2[name] = 0
-  in3[name] = 0
-  out2[name] = 0
-  out3[name] = 0
-  for(i=3; i<NF; i++){
-    if($i=="same" && $(i+1)=="as"){
-      sym = $(i+2)
-      sub(/,/,"",sym)
-      val = tk[sym]
-      op[name] = val
-      used[val] = 1
-      sameas[val] = sym
-      def[val] = name
-    }
-    x = $i
-    sub(",","",x)
-    if(x=="jump"){
-      jump[name] = 1
-    }else if(x=="in1"){
-      in1[name] = 1
-    }else if(x=="in2"){
-      in2[name] = 1
-    }else if(x=="in3"){
-      in3[name] = 1
-    }else if(x=="out2"){
-      out2[name] = 1
-    }else if(x=="out3"){
-      out3[name] = 1
-    }
-  }
-  order[n_op++] = name;
-}
-
-# Assign numbers to all opcodes and output the result.
-END {
-  cnt = 0
-  max = 0
-  print "/* Automatically generated.  Do not edit */"
-  print "/* See the mkopcodeh.awk script for details */"
-  op["OP_Noop"] = -1;
-  order[n_op++] = "OP_Noop";
-  op["OP_Explain"] = -1;
-  order[n_op++] = "OP_Explain";
-
-  # Assign small values to opcodes that are processed by resolveP2Values()
-  # to make code generation for the switch() statement smaller and faster.
-  for(i=0; i<n_op; i++){
-    name = order[i];
-    if( op[name]>=0 ) continue;
-    if( name=="OP_Transaction"   \
-     || name=="OP_AutoCommit"    \
-     || name=="OP_Savepoint"     \
-     || name=="OP_Checkpoint"    \
-     || name=="OP_Vacuum"        \
-     || name=="OP_JournalMode"   \
-     || name=="OP_VUpdate"       \
-     || name=="OP_VFilter"       \
-     || name=="OP_Next"          \
-     || name=="OP_NextIfOpen"    \
-     || name=="OP_SorterNext"    \
-     || name=="OP_Prev"          \
-     || name=="OP_PrevIfOpen"    \
-    ){
-      cnt++
-      while( used[cnt] ) cnt++
-      op[name] = cnt
-      used[cnt] = 1
-      def[cnt] = name
-    }
-  }
-
-  # Generate the numeric values for opcodes
-  for(i=0; i<n_op; i++){
-    name = order[i];
-    if( op[name]<0 ){
-      cnt++
-      while( used[cnt] ) cnt++
-      op[name] = cnt
-      used[cnt] = 1
-      def[cnt] = name
-    }
-  }
-  max = cnt
-  for(i=1; i<=max; i++){
-    if( !used[i] ){
-      def[i] = "OP_NotUsed_" i 
-    }
-    printf "#define %-16s %3d", def[i], i
-    com = ""
-    if( sameas[i] ){
-      com = "same as " sameas[i]
-    }
-    x = synopsis[def[i]]
-    if( x ){
-      if( com=="" ){
-        com = "synopsis: " x
-      } else {
-        com = com ", synopsis: " x
-      }
-    }
-    if( com!="" ){
-      printf " /* %-42s */", com
-    }
-    printf "\n"
-  }
-
-  # Generate the bitvectors:
-  #
-  #  bit 0:     jump
-  #  bit 1:     pushes a result onto stack
-  #  bit 2:     output to p1.  release p1 before opcode runs
-  #
-  for(i=0; i<=max; i++){
-    name = def[i]
-    a0 = a1 = a2 = a3 = a4 = a5 = a6 = a7 = 0
-    if( jump[name] ) a0 = 1;
-    if( in1[name] ) a2 = 2;
-    if( in2[name] ) a3 = 4;
-    if( in3[name] ) a4 = 8;
-    if( out2[name] ) a5 = 16;
-    if( out3[name] ) a6 = 32;
-    bv[i] = a0+a1+a2+a3+a4+a5+a6;
-  }
-  print "\n"
-  print "/* Properties such as \"out2\" or \"jump\" that are specified in"
-  print "** comments following the \"case\" for each opcode in the vdbe.c"
-  print "** are encoded into bitvectors as follows:"
-  print "*/"
-  print "#define OPFLG_JUMP            0x0001  /* jump:  P2 holds jmp target */"
-  print "#define OPFLG_IN1             0x0002  /* in1:   P1 is an input */"
-  print "#define OPFLG_IN2             0x0004  /* in2:   P2 is an input */"
-  print "#define OPFLG_IN3             0x0008  /* in3:   P3 is an input */"
-  print "#define OPFLG_OUT2            0x0010  /* out2:  P2 is an output */"
-  print "#define OPFLG_OUT3            0x0020  /* out3:  P3 is an output */"
-  print "#define OPFLG_INITIALIZER {\\"
-  for(i=0; i<=max; i++){
-    if( i%8==0 ) printf("/* %3d */",i)
-    printf " 0x%02x,", bv[i]
-    if( i%8==7 ) printf("\\\n");
-  }
-  print "}"
-  if( 0 ){
-    print "\n/* Bitmask to indicate which fields (P1..P5) of each opcode are"
-    print "** actually used.\n*/"
-    print "#define OP_PARAM_USED_INITIALIZER {\\"
-    for(i=0; i<=max; i++){
-      if( i%8==0 ) printf("/* %3d */",i)
-      printf " 0x%02x,", paramused[def[i]]
-      if( i%8==7 ) printf("\\\n");
-    }
-    print "}"
-  }
-}
diff --git a/tool/mkopcodeh.tcl b/tool/mkopcodeh.tcl
new file mode 100644 (file)
index 0000000..4c36f24
--- /dev/null
@@ -0,0 +1,230 @@
+#!/usr/bin/tclsh
+#
+# Generate the file opcodes.h.
+#
+# This TCL script scans a concatenation of the parse.h output file from the
+# parser and the vdbe.c source file in order to generate the opcodes numbers
+# for all opcodes.  
+#
+# The lines of the vdbe.c that we are interested in are of the form:
+#
+#       case OP_aaaa:      /* same as TK_bbbbb */
+#
+# The TK_ comment is optional.  If it is present, then the value assigned to
+# the OP_ is the same as the TK_ value.  If missing, the OP_ value is assigned
+# a small integer that is different from every other OP_ value.
+#
+# We go to the trouble of making some OP_ values the same as TK_ values
+# as an optimization.  During parsing, things like expression operators
+# are coded with TK_ values such as TK_ADD, TK_DIVIDE, and so forth.  Later
+# during code generation, we need to generate corresponding opcodes like
+# OP_Add and OP_Divide.  By making TK_ADD==OP_Add and TK_DIVIDE==OP_Divide,
+# code to translate from one to the other is avoided.  This makes the
+# code generator run (infinitesimally) faster and more importantly it makes
+# the library footprint smaller.
+#
+# This script also scans for lines of the form:
+#
+#       case OP_aaaa:       /* jump, in1, in2, in3, out2-prerelease, out3 */
+#
+# When such comments are found on an opcode, it means that certain
+# properties apply to that opcode.  Set corresponding flags using the
+# OPFLG_INITIALIZER macro.
+#
+
+set in stdin
+set currentOp {}
+set nOp 0
+while {![eof $in]} {
+  set line [gets $in]
+
+  # Remember the TK_ values from the parse.h file. 
+  # NB:  The "TK_" prefix stands for "ToKen", not the graphical Tk toolkit
+  # commonly associated with TCL.
+  #
+  if {[regexp {^#define TK_} $line]} {
+    set tk([lindex $line 1]) [lindex $line 2]
+    continue
+  }
+
+  # Find "/* Opcode: " lines in the vdbe.c file.  Each one introduces
+  # a new opcode.  Remember which parameters are used.
+  #
+  if {[regexp {^.. Opcode: } $line]} {
+    set currentOp OP_[lindex $line 2]
+    set m 0
+    foreach term $line {
+      switch $term {
+        P1 {incr m 1}
+        P2 {incr m 2}
+        P3 {incr m 4}
+        P4 {incr m 8}
+        P5 {incr m 16}
+      }
+    }
+    set paramused($currentOp) $m
+  }
+
+  # Find "** Synopsis: " lines that follow Opcode:
+  #
+  if {[regexp {^.. Synopsis: (.*)} $line all x] && $currentOp!=""} {
+    set synopsis($currentOp) [string trim $x]
+  }
+
+  # Scan for "case OP_aaaa:" lines in the vdbe.c file
+  #
+  if {[regexp {^case OP_} $line]} {
+    set line [split $line]
+    set name [string trim [lindex $line 1] :]
+    set op($name) -1
+    set jump($name) 0
+    set in1($name) 0
+    set in2($name) 0
+    set in3($name) 0
+    set out1($name) 0
+    set out2($name) 0
+    for {set i 3} {$i<[llength $line]-1} {incr i} {
+       switch [string trim [lindex $line $i] ,] {
+         same {
+           incr i
+           if {[lindex $line $i]=="as"} {
+             incr i
+             set sym [string trim [lindex $line $i] ,]
+             set val $tk($sym)
+             set op($name) $val
+             set used($val) 1
+             set sameas($val) $sym
+             set def($val) $name
+           }
+         }
+         jump {set jump($name) 1}
+         in1  {set in1($name) 1}
+         in2  {set in2($name) 1}
+         in3  {set in3($name) 1}
+         out2 {set out2($name) 1}
+         out3 {set out3($name) 1}
+       }
+    }
+    set order($nOp) $name
+    incr nOp
+  }
+}
+
+# Assign numbers to all opcodes and output the result.
+#
+set cnt 0
+set max 0
+puts "/* Automatically generated.  Do not edit */"
+puts "/* See the tool/mkopcodeh.tcl script for details */"
+set op(OP_Noop) -1
+set order($nOp) OP_Noop
+incr nOp
+set op(OP_Explain) -1
+set order($nOp) OP_Explain
+incr nOp
+
+# The following are the opcodes that are processed by resolveP2Values()
+#
+set rp2v_ops {
+  OP_Transaction
+  OP_AutoCommit
+  OP_Savepoint
+  OP_Checkpoint
+  OP_Vacuum
+  OP_JournalMode
+  OP_VUpdate
+  OP_VFilter
+  OP_Next
+  OP_NextIfOpen
+  OP_SorterNext
+  OP_Prev
+  OP_PrevIfOpen
+}
+
+# Assign small values to opcodes that are processed by resolveP2Values()
+# to make code generation for the switch() statement smaller and faster.
+#
+set cnt 0
+for {set i 0} {$i<$nOp} {incr i} {
+  set name $order($i)
+  if {[lsearch $rp2v_ops $name]>=0} {
+    incr cnt
+    while {[info exists used($cnt)]} {incr cnt}
+    set op($name) $cnt
+    set used($cnt) 1
+    set def($cnt) $name
+  }
+}
+
+# Generate the numeric values for remaining opcodes
+#
+for {set i 0} {$i<$nOp} {incr i} {
+  set name $order($i)
+  if {$op($name)<0} {
+    incr cnt
+    while {[info exists used($cnt)]} {incr cnt}
+    set op($name) $cnt
+    set used($cnt) 1
+    set def($cnt) $name
+  }
+}
+set max $cnt
+for {set i 1} {$i<=$nOp} {incr i} {
+  if {![info exists used($i)]} {
+    set def($i) "OP_NotUsed_$i"
+  }
+  set name $def($i)
+  puts -nonewline [format {#define %-16s %3d} $name $i]
+  set com {}
+  if {[info exists sameas($i)]} {
+    set com "same as $sameas($i)"
+  }
+  if {[info exists synopsis($name)]} {
+    set x $synopsis($name)
+    if {$com==""} {
+      set com "synopsis: $x"
+    } else {
+      append com ", synopsis: $x"
+    }
+  }
+  if {$com!=""} {
+    puts -nonewline [format " /* %-42s */" $com]
+  }
+  puts ""
+}
+
+# Generate the bitvectors:
+#
+set bv(0) 0
+for {set i 1} {$i<=$max} {incr i} {
+  set name $def($i)
+  if {[info exists jump($name)] && $jump($name)} {set a0 1}  {set a0 0}
+  if {[info exists in1($name)] && $in1($name)}   {set a1 2}  {set a1 0}
+  if {[info exists in2($name)] && $in2($name)}   {set a2 4}  {set a2 0}
+  if {[info exists in3($name)] && $in3($name)}   {set a3 8}  {set a3 0}
+  if {[info exists out2($name)] && $out2($name)} {set a4 16} {set a4 0}
+  if {[info exists out3($name)] && $out3($name)} {set a5 32} {set a5 0}
+  set bv($i) [expr {$a0+$a1+$a2+$a3+$a4+$a5}]
+}
+puts ""
+puts "/* Properties such as \"out2\" or \"jump\" that are specified in"
+puts "** comments following the \"case\" for each opcode in the vdbe.c"
+puts "** are encoded into bitvectors as follows:"
+puts "*/"
+puts "#define OPFLG_JUMP            0x0001  /* jump:  P2 holds jmp target */"
+puts "#define OPFLG_IN1             0x0002  /* in1:   P1 is an input */"
+puts "#define OPFLG_IN2             0x0004  /* in2:   P2 is an input */"
+puts "#define OPFLG_IN3             0x0008  /* in3:   P3 is an input */"
+puts "#define OPFLG_OUT2            0x0010  /* out2:  P2 is an output */"
+puts "#define OPFLG_OUT3            0x0020  /* out3:  P3 is an output */"
+puts "#define OPFLG_INITIALIZER \173\\"
+for {set i 0} {$i<=$max} {incr i} {
+  if {$i%8==0} {
+    puts -nonewline [format "/* %3d */" $i]
+  }
+  puts -nonewline [format " 0x%02x," $bv($i)]
+  if {$i%8==7} {
+    puts "\\"
+  }
+}
+puts "\175"