about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--subx/Readme.md3
-rw-r--r--subx/apps/dquotes.subx8
-rw-r--r--subx/apps/testsbin0 -> 32933 bytes
-rw-r--r--subx/apps/tests.subx279
-rwxr-xr-xsubx/test_apps80
-rwxr-xr-xsubx/translate4
6 files changed, 333 insertions, 41 deletions
diff --git a/subx/Readme.md b/subx/Readme.md
index ba1daf8a..2f3eda88 100644
--- a/subx/Readme.md
+++ b/subx/Readme.md
@@ -348,7 +348,7 @@ runnable on a Linux system running on Intel x86 processors, either 32- or
   - examples/ex8.subx (✓)
   - examples/ex9.subx (✓)
   - examples/ex10.subx (✓)
-  - examples/ex11.subx
+  - examples/ex11.subx (✓)
   - examples/ex12.subx (✓)
   - apps/factorial.subx
   - apps/crenshaw2-1.subx
@@ -359,6 +359,7 @@ runnable on a Linux system running on Intel x86 processors, either 32- or
   - apps/pack.subx
   - apps/assort.subx
   - apps/dquotes.subx
+  - apps/tests.subx
 
 * Testable, dependency-injected vocabulary of primitives
   - Streams: `read()`, `write()`. (✓)
diff --git a/subx/apps/dquotes.subx b/subx/apps/dquotes.subx
index eb0575cc..9331843c 100644
--- a/subx/apps/dquotes.subx
+++ b/subx/apps/dquotes.subx
@@ -2,11 +2,11 @@
 # Replace them with references to new variables in the data segment.
 #
 # To run (from the subx/ directory):
-#   $ ./subx translate *.subx apps/dquote.subx -o apps/dquote
+#   $ ./subx translate *.subx apps/dquotes.subx -o apps/dquotes
 #   $ cat x
 #   == code
 #   ab "cd ef"/imm32
-#   $ cat x  |./subx run apps/dquote
+#   $ cat x  |./subx run apps/dquotes
 #   == code
 #   ab __string1/imm32
 #   == data
@@ -84,7 +84,7 @@ convert:  # in : (address buffered-file), out : (address buffered-file) -> <void
     # pseudocode:
     #   var line = new-stream(512, 1)
     #   var new-data-segment = new-stream(Heap, Segment-size, 1)
-    #   write-stream(new-data-segment, "== data\n")
+    #   write(new-data-segment, "== data\n")
     #   while true
     #     clear-stream(line)
     #     read-line-buffered(in, line)
@@ -196,7 +196,7 @@ $convert:check-for-comment:
     3d/compare-EAX-and  0x23/imm32/hash
     74/jump-if-equal  $convert:word-loop/disp8
 $convert:check-for-string-literal:
-    3d/compare-EAX-and  0x22/imm32/hash
+    3d/compare-EAX-and  0x22/imm32/dquote
     75/jump-if-not-equal  $convert:regular-word/disp8
 $convert:string-literal:
     # process-string-literal(word-slice, out, new-data-segment)
diff --git a/subx/apps/tests b/subx/apps/tests
new file mode 100644
index 00000000..2e1a23c1
--- /dev/null
+++ b/subx/apps/tests
Binary files differdiff --git a/subx/apps/tests.subx b/subx/apps/tests.subx
new file mode 100644
index 00000000..12f4902b
--- /dev/null
+++ b/subx/apps/tests.subx
@@ -0,0 +1,279 @@
+# Generate code for a new function called 'run-tests' which calls in sequence
+# all functions starting with 'test-'.
+
+== code
+#   instruction                     effective address                                                   register    displacement    immediate
+# . op          subop               mod             rm32          base        index         scale       r32
+# . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+
+Entry:
+    # Heap = new-segment(Heap-size)
+    # . . push args
+    68/push  Heap/imm32
+    68/push  Heap-size/imm32
+    # . . call
+    e8/call  new-segment/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+    # initialize-trace-stream(256KB)
+    # . . push args
+    68/push  0x40000/imm32/256KB
+    # . . call
+    e8/call  initialize-trace-stream/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+
+    # run tests if necessary, convert stdin if not
+    # . prolog
+    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+    # initialize heap
+    # - if argc > 1 and argv[1] == "test", then return run_tests()
+    # . argc > 1
+    81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0/disp8         1/imm32           # compare *EBP
+    7e/jump-if-lesser-or-equal  $run-main/disp8
+    # . argv[1] == "test"
+    # . . push args
+    68/push  "test"/imm32
+    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+    # . . call
+    e8/call  kernel-string-equal?/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+    # . check result
+    3d/compare-EAX-and  1/imm32
+    75/jump-if-not-equal  $run-main/disp8
+    # . run-tests()
+    e8/call  run-tests/disp32
+    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
+    eb/jump  $main:end/disp8
+$run-main:
+    # - otherwise convert stdin
+    # convert(Stdin, Stdout)
+    # . . push args
+    68/push  Stdout/imm32
+    68/push  Stdin/imm32
+    # . . call
+    e8/call  convert/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+    # . syscall(exit, 0)
+    bb/copy-to-EBX  0/imm32
+$main:end:
+    b8/copy-to-EAX  1/imm32/exit
+    cd/syscall  0x80/imm8
+
+convert:  # in : (address buffered-file), out : (address buffered-file) -> <void>
+    # pseudocode
+    #   bool tests-found = false
+    #   var line = new-stream(512, 1)
+    #   var new-code-segment = new-stream(Segment-size, 1)
+    #   write(new-code-segment, "\n==code\n")
+    #   write(new-code-segment, "run-tests:\n")
+    #   while true
+    #     clear-stream(line)
+    #     read-line-buffered(in, line)
+    #     if (line->write == 0) break               # end of file
+    #     var word-slice = next-word(line)
+    #     if is-label?(word-slice)
+    #       if slice-starts-with?(word-slice, "test-")
+    #         tests-found = true
+    #         write(new-code-segment, "  e8/call  ")
+    #         write-slice(new-code-segment, word-slice)
+    #         write(new-code-segment, "/disp32\n")
+    #     rewind-stream(line)
+    #     write-stream-data(out, line)
+    #   if tests-found
+    #     write(new-code-segment, "  c3/return\n")
+    #     write-stream-data(out, new-code-segment)
+    #   flush(out)
+    #
+    # . prolog
+    55/push-EBP
+    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+    # . save registers
+    50/push-EAX
+    51/push-ECX
+    52/push-EDX
+    53/push-EBX
+    57/push-EDI
+    # var line/ECX : (address stream byte) = stream(512)
+    81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x200/imm32       # subtract from ESP
+    68/push  0x200/imm32/length
+    68/push  0/imm32/read
+    68/push  0/imm32/write
+    89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+    # var word-slice/EDX = {0, 0}
+    68/push  0/imm32/end
+    68/push  0/imm32/start
+    89/copy                         3/mod/direct    2/rm32/EDX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDX
+    # tests-found?/EBX = false
+    31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
+    # new-code-segment/EDI = new-stream(Heap, Segment-size, 1)
+    # . EAX = new-stream(Heap, Segment-size, 1)
+    # . . push args
+    68/push  1/imm32
+    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Segment-size/disp32               # push *Segment-size
+    68/push  Heap/imm32
+    # . . call
+    e8/call  new-stream/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+    # . EDI = EAX
+    89/copy                         3/mod/direct    7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy EAX to EDI
+    # write(new-code-segment, "\n== code\n")
+    # . . push args
+    68/push  "\n== code\n"/imm32
+    57/push-EDI
+    # . . call
+    e8/call  write/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+    # write(new-code-segment, "run-tests:\n")
+    # . . push args
+    68/push  "run-tests:\n"/imm32
+    57/push-EDI
+    # . . call
+    e8/call  write/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+$convert:loop:
+    # clear-stream(line)
+    # . . push args
+    51/push-ECX
+    # . . call
+    e8/call  clear-stream/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+    # read-line-buffered(in, line)
+    # . . push args
+    51/push-ECX
+    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+    # . . call
+    e8/call  read-line-buffered/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+$convert:check0:
+    # if (line->write == 0) break
+    81          7/subop/compare     0/mod/indirect  1/rm32/ECX    .           .             .           .           .               0/imm32           # compare *ECX
+    0f 84/jump-if-equal  $convert:break/disp32
+    # next-word(line, word-slice)
+    # . . push args
+    52/push-EDX
+    51/push-ECX
+    # . . call
+    e8/call  next-word/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+$convert:check-for-label:
+    # if (!is-label?(word-slice)) continue
+    # . EAX = is-label?(word-slice)
+    # . . push args
+    52/push-EDX
+    # . . call
+    e8/call  is-label?/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+    # . if (EAX == 0) continue
+    3d/compare-EAX-and  0/imm32
+    74/jump-if-equal  $convert:continue/disp8
+$convert:check-label-prefix:
+    # strip trailing ':' from word-slice
+    ff          1/subop/decrement   1/mod/*+disp8   2/rm32/EDX    .           .             .           .           4/disp8         .                 # decrement *(EDX+4)
+    # if !slice-starts-with?(word-slice, "test-") continue
+    # . . push args
+    68/push  "test-"/imm32
+    52/push-EDX
+    # . . call
+    e8/call  slice-starts-with?/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+    # . if (EAX == 0) break
+    3d/compare-EAX-and  0/imm32
+    74/jump-if-equal  $convert:continue/disp8
+$convert:call-test-function:
+    # tests-found? = true
+    bb/copy-to-EBX  1/imm32/true
+    # write(new-code-segment, "  e8/call  ")
+    # . . push args
+    68/push  "  e8/call  "/imm32
+    57/push-EDI
+    # . . call
+    e8/call  write/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+    # write-slice(new-code-segment, word-slice)
+    # . . push args
+    52/push-EDX
+    57/push-EDI
+    # . . call
+    e8/call  write-slice/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+    # write(new-code-segment, "/disp32\n")
+    # . . push args
+    68/push  "/disp32\n"/imm32
+    57/push-EDI
+    # . . call
+    e8/call  write/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+$convert:continue:
+    # rewind-stream(line)
+    # . . push args
+    51/push-ECX
+    # . . call
+    e8/call  rewind-stream/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+    # write-stream-data(out, line)
+    # . . push args
+    51/push-ECX
+    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+    # . . call
+    e8/call  write-stream-data/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+    # loop
+    e9/jump  $convert:loop/disp32
+$convert:break:
+    # if (!tests-found?) goto end
+    81          7/subop/compare     3/mod/direct    3/rm32/EBX    .           .             .           .           .               0/imm32           # compare EBX
+    74/jump-if-equal  $convert:end/disp8
+    # write(new-code-segment, "  c3/return\n")
+    # . . push args
+    68/push  "  c3/return\n"/imm32
+    57/push-EDI
+    # . . call
+    e8/call  write/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+    # write-stream-data(out, new-code-segment)
+    # . . push args
+    57/push-EDI
+    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+    # . . call
+    e8/call  write-stream-data/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+$convert:end:
+    # flush(out)
+    # . . push args
+    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+    # . . call
+    e8/call  flush/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+    # . reclaim locals
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x214/imm32       # add to ESP
+    # . restore registers
+    5f/pop-to-EDI
+    5b/pop-to-EBX
+    5a/pop-to-EDX
+    59/pop-to-ECX
+    58/pop-to-EAX
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+    5d/pop-to-EBP
+    c3/return
+
+# . . vim:nowrap:textwidth=0
diff --git a/subx/test_apps b/subx/test_apps
index 5955b399..ed67a295 100755
--- a/subx/test_apps
+++ b/subx/test_apps
@@ -226,102 +226,112 @@ test `uname` = 'Linux'  &&  {
   echo
 }
 
+echo tests
+./subx translate 0*.subx apps/subx-common.subx apps/tests.subx  -o apps/tests
+[ "$1" != record ]  &&  git diff --exit-code apps/tests
+./subx run apps/tests test
+echo
+test `uname` = 'Linux'  &&  {
+  apps/tests test
+  echo
+}
+
 echo "== translating using SubX"
 
 echo ex1
-cat examples/ex1.subx |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex1 -
+cat examples/ex1.subx |./subx_bin run apps/tests |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex1 -
 test `uname` = 'Linux'  &&  {
-  cat examples/ex1.subx |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex1 -
+  cat examples/ex1.subx |apps/tests |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex1 -
 }
 
 echo ex2
-cat examples/ex2.subx |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex2 -
+cat examples/ex2.subx |./subx_bin run apps/tests |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex2 -
 test `uname` = 'Linux'  &&  {
-  cat examples/ex2.subx |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex2 -
+  cat examples/ex2.subx |apps/tests |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex2 -
 }
 
 echo ex3
-cat examples/ex3.subx |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex3 -
+cat examples/ex3.subx |./subx_bin run apps/tests |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex3 -
 test `uname` = 'Linux'  &&  {
-  cat examples/ex3.subx |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex3 -
+  cat examples/ex3.subx |apps/tests |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex3 -
 }
 
 echo ex4
-cat examples/ex4.subx |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex4 -
+cat examples/ex4.subx |./subx_bin run apps/tests |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex4 -
 test `uname` = 'Linux'  &&  {
-  cat examples/ex4.subx |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex4 -
+  cat examples/ex4.subx |apps/tests |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex4 -
 }
 
 echo ex5
-cat examples/ex5.subx |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex5 -
+cat examples/ex5.subx |./subx_bin run apps/tests |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex5 -
 test `uname` = 'Linux'  &&  {
-  cat examples/ex5.subx |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex5 -
+  cat examples/ex5.subx |apps/tests |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex5 -
 }
 
 echo ex6
-cat examples/ex6.subx |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex6 -
+cat examples/ex6.subx |./subx_bin run apps/tests |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex6 -
 test `uname` = 'Linux'  &&  {
-  cat examples/ex6.subx |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex6 -
+  cat examples/ex6.subx |apps/tests |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex6 -
 }
 
 echo ex7
-cat examples/ex7.subx |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex7 -
+cat examples/ex7.subx |./subx_bin run apps/tests |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex7 -
 test `uname` = 'Linux'  &&  {
-  cat examples/ex7.subx |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex7 -
+  cat examples/ex7.subx |apps/tests |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex7 -
 }
 
 echo ex8
-cat examples/ex8.subx |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex8 -
+cat examples/ex8.subx |./subx_bin run apps/tests |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex8 -
 test `uname` = 'Linux'  &&  {
-  cat examples/ex8.subx |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex8 -
+  cat examples/ex8.subx |apps/tests |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex8 -
 }
 
 echo ex9
-cat examples/ex9.subx |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex9 -
+cat examples/ex9.subx |./subx_bin run apps/tests |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex9 -
 test `uname` = 'Linux'  &&  {
-  cat examples/ex9.subx |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex9 -
+  cat examples/ex9.subx |apps/tests |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex9 -
 }
 
 echo ex10
-cat examples/ex10.subx |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex10 -
+cat examples/ex10.subx |./subx_bin run apps/tests |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex10 -
 test `uname` = 'Linux'  &&  {
-  cat examples/ex10.subx |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex10 -
+  cat examples/ex10.subx |apps/tests |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex10 -
 }
 
-#? echo ex11
-#? cat examples/ex11.subx |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex11 -
-#? test `uname` = 'Linux'  &&  {
-#?   cat examples/ex11.subx |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex11 -
-#? }
+echo ex11
+cat examples/ex11.subx |./subx_bin run apps/tests |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex11 -
+test `uname` = 'Linux'  &&  {
+  cat examples/ex11.subx |apps/tests |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex11 -
+}
 
 echo ex12
-cat examples/ex12.subx |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex12 -
+cat examples/ex12.subx |./subx_bin run apps/tests |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff examples/ex12 -
 test `uname` = 'Linux'  &&  {
-  cat examples/ex12.subx |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex12 -
+  cat examples/ex12.subx |apps/tests |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff examples/ex12 -
 }
 
 #? echo factorial
-#? cat 0*.subx apps/subx-common.subx apps/factorial.subx |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff apps/factorial -
+#? cat 0*.subx apps/subx-common.subx apps/factorial.subx |./subx_bin run apps/tests |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff apps/factorial -
 #? test `uname` = 'Linux'  &&  {
-#?   cat apps/factorial.subx |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff apps/factorial -
+#?   cat apps/factorial.subx |apps/tests |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff apps/factorial -
 #? }
 
 #? echo crenshaw2-1
-#? cat 0*.subx apps/subx-common.subx apps/crenshaw2-1.subx |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff apps/crenshaw2-1 -
+#? cat 0*.subx apps/subx-common.subx apps/crenshaw2-1.subx |./subx_bin run apps/tests |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff apps/crenshaw2-1 -
 #? test `uname` = 'Linux'  &&  {
-#?   cat apps/crenshaw2-1.subx |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff apps/crenshaw2-1 -
+#?   cat apps/crenshaw2-1.subx |apps/tests |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff apps/crenshaw2-1 -
 #? }
 
 #? echo crenshaw2-1b
-#? cat 0*.subx apps/subx-common.subx apps/crenshaw2-1b.subx |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff apps/crenshaw2-1b -
+#? cat 0*.subx apps/subx-common.subx apps/crenshaw2-1b.subx |./subx_bin run apps/tests |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff apps/crenshaw2-1b -
 #? test `uname` = 'Linux'  &&  {
-#?   cat apps/crenshaw2-1b.subx |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff apps/crenshaw2-1b -
+#?   cat apps/crenshaw2-1b.subx |apps/tests |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff apps/crenshaw2-1b -
 #? }
 
 #? echo handle
-#? cat 0*.subx apps/subx-common.subx apps/handle.subx |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff apps/handle -
+#? cat 0*.subx apps/subx-common.subx apps/handle.subx |./subx_bin run apps/tests |./subx_bin run apps/dquotes |./subx_bin run apps/assort |./subx_bin run apps/pack |./subx_bin run apps/survey |./subx_bin run apps/hex |diff apps/handle -
 #? test `uname` = 'Linux'  &&  {
-#?   cat apps/handle.subx |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff apps/handle -
+#?   cat apps/handle.subx |apps/tests |apps/dquotes |apps/assort |apps/pack |apps/survey |apps/hex |diff apps/handle -
 #? }
 
 exit 0
diff --git a/subx/translate b/subx/translate
index 979c006c..f5957512 100755
--- a/subx/translate
+++ b/subx/translate
@@ -18,7 +18,9 @@ build
 
 echo `cat $* |grep -v '^\s*#\|^\s*$' |wc -l` lines
 
-cat $*          |./subx_bin run apps/dquotes  > a.dquotes
+cat $*          |./subx_bin run apps/tests    > a.tests
+
+cat a.tests     |./subx_bin run apps/dquotes  > a.dquotes
 
 cat a.dquotes   |./subx_bin run apps/assort   > a.assort