This commit is contained in:
Kartik Agaram 2020-01-01 17:23:29 -08:00
parent 1b050736ee
commit 113bae7311
43 changed files with 89 additions and 98 deletions

View File

@ -27,7 +27,7 @@ put_new(Help, "syntax",
"after a '/', but they can never contain whitespace. Metadata has no effect\n" "after a '/', but they can never contain whitespace. Metadata has no effect\n"
"at runtime, but can be handy when rewriting macros.\n" "at runtime, but can be handy when rewriting macros.\n"
"\n" "\n"
"Check out the examples in the examples/ directory.\n" "Check out the example programs in the apps/ directory, particularly apps/ex*.\n"
); );
:(before "End Help Contents") :(before "End Help Contents")
cerr << " syntax\n"; cerr << " syntax\n";

View File

@ -48,7 +48,7 @@ In priority order:
You get a thin syntax called SubX for programming in (a subset of) x86 machine You get a thin syntax called SubX for programming in (a subset of) x86 machine
code. (A memory-safe compiled language is [being designed](http://akkartik.name/post/mu-2019-2).) code. (A memory-safe compiled language is [being designed](http://akkartik.name/post/mu-2019-2).)
Here's a program (`examples/ex1.subx`) that returns 42: Here's a program (`apps/ex1.subx`) that returns 42:
```sh ```sh
bb/copy-to-ebx 0x2a/imm32 # 42 in hex bb/copy-to-ebx 0x2a/imm32 # 42 in hex
@ -59,8 +59,8 @@ Here's a program (`examples/ex1.subx`) that returns 42:
You can generate tiny zero-dependency ELF binaries with it that run on Linux. You can generate tiny zero-dependency ELF binaries with it that run on Linux.
```sh ```sh
$ ./subx translate init.linux examples/ex1.subx -o examples/ex1 # on Linux or BSD or Mac $ ./subx translate init.linux apps/ex1.subx -o apps/ex1 # on Linux or BSD or Mac
$ ./examples/ex1 # only on Linux $ ./apps/ex1 # only on Linux
$ echo $? $ echo $?
42 42
``` ```
@ -72,7 +72,7 @@ You can run the generated binaries on an interpreter/VM for better error
messages. messages.
```sh ```sh
$ ./subx run examples/ex1 # on Linux or BSD or Mac $ ./subx run apps/ex1 # on Linux or BSD or Mac
$ echo $? $ echo $?
42 42
``` ```
@ -80,11 +80,11 @@ messages.
Emulated runs can generate a trace that permits [time-travel debugging](https://github.com/akkartik/mu/blob/master/tools/browse_trace.readme.md). Emulated runs can generate a trace that permits [time-travel debugging](https://github.com/akkartik/mu/blob/master/tools/browse_trace.readme.md).
```sh ```sh
$ ./subx --debug translate init.linux examples/factorial.subx -o examples/factorial $ ./subx --debug translate init.linux apps/factorial.subx -o apps/factorial
saving address->label information to 'labels' saving address->label information to 'labels'
saving address->source information to 'source_lines' saving address->source information to 'source_lines'
$ ./subx --debug --trace run examples/factorial $ ./subx --debug --trace run apps/factorial
saving trace to 'last_run' saving trace to 'last_run'
$ tools/browse_trace last_run # text-mode debugger UI $ tools/browse_trace last_run # text-mode debugger UI
@ -111,14 +111,14 @@ You can use SubX to translate itself. For example, running natively on Linux:
$ chmod +x hex survey pack assort dquotes tests $ chmod +x hex survey pack assort dquotes tests
# use the generated translator phases to translate SubX programs # use the generated translator phases to translate SubX programs
$ cat init.linux examples/ex1.subx |./tests |./dquotes |./assort |./pack |./survey |./hex > a.elf $ cat init.linux apps/ex1.subx |./tests |./dquotes |./assort |./pack |./survey |./hex > a.elf
$ chmod +x a.elf $ chmod +x a.elf
$ ./a.elf $ ./a.elf
$ echo $? $ echo $?
42 42
# or, automating the above steps # or, automating the above steps
$ ./translate_subx init.linux examples/ex1.subx $ ./translate_subx init.linux apps/ex1.subx
$ ./a.elf $ ./a.elf
$ echo $? $ echo $?
42 42
@ -142,7 +142,7 @@ work on a cloud server.)
$ sudo apt install util-linux nasm xorriso # maybe also dosfstools and mtools $ sudo apt install util-linux nasm xorriso # maybe also dosfstools and mtools
# package up a "hello world" program with a third-party kernel into mu_soso.iso # package up a "hello world" program with a third-party kernel into mu_soso.iso
# requires sudo # requires sudo
$ ./gen_soso_iso init.soso examples/ex6.subx $ ./gen_soso_iso init.soso apps/ex6.subx
# try it out # try it out
$ qemu-system-i386 -cdrom mu_soso.iso $ qemu-system-i386 -cdrom mu_soso.iso
``` ```
@ -154,7 +154,7 @@ kernel; that number will gradually go down.)
```sh ```sh
$ sudo apt install build-essential flex bison wget libelf-dev libssl-dev xorriso $ sudo apt install build-essential flex bison wget libelf-dev libssl-dev xorriso
$ ./gen_linux_iso init.linux examples/ex6.subx $ ./gen_linux_iso init.linux apps/ex6.subx
$ qemu-system-x86_64 -m 256M -cdrom mu.iso -boot d $ qemu-system-x86_64 -m 256M -cdrom mu.iso -boot d
``` ```
@ -299,7 +299,7 @@ and digest it:
Here's a more meaty example: Here's a more meaty example:
<img alt='examples/ex3.subx' src='html/ex3.png'> <img alt='apps/ex3.subx' src='html/ex3.png'>
This program sums the first 10 natural numbers. By convention I use horizontal This program sums the first 10 natural numbers. By convention I use horizontal
tabstops to help read instructions, dots to help follow the long lines, tabstops to help read instructions, dots to help follow the long lines,
@ -313,8 +313,8 @@ like decimal numbers.
Try running this example now: Try running this example now:
```sh ```sh
$ ./subx translate init.linux examples/ex3.subx -o examples/ex3 $ ./subx translate init.linux apps/ex3.subx -o apps/ex3
$ ./subx run examples/ex3 $ ./subx run apps/ex3
$ echo $? $ echo $?
55 55
``` ```
@ -322,7 +322,7 @@ $ echo $?
If you're on Linux you can also run it natively: If you're on Linux you can also run it natively:
```sh ```sh
$ ./examples/ex3 $ ./apps/ex3
$ echo $? $ echo $?
55 55
``` ```
@ -413,13 +413,14 @@ SubX will transparently copy it to the `data` segment and replace it with its
address. Strings are the only place where a SubX word is allowed to contain address. Strings are the only place where a SubX word is allowed to contain
spaces. spaces.
That should be enough information for writing SubX programs. The `examples/` That should be enough information for writing SubX programs. The `apps/`
directory provides some fodder for practice, giving a more gradual introduction directory provides some fodder for practice in the `apps/ex*` files, giving a
to SubX features. This repo includes the binary for all examples. At any more gradual introduction to SubX features. This repo includes binaries for
commit, an example's binary should be identical bit for bit with the result of all examples. At any commit, an example's binary should be identical bit for
translating the corresponding `.subx` file. The binary should also be natively bit with the result of translating the corresponding `.subx` file. The binary
runnable on a Linux system running on Intel x86 processors, either 32- or should also be natively runnable on a Linux system running on Intel x86
64-bit. If either of these invariants is broken it's a bug on my part. processors, either 32- or 64-bit. If either of these invariants is broken it's
a bug on my part.
## Running ## Running

View File

@ -1,2 +1,11 @@
Larger programs than in the examples/ subdirectory, combining the techniques Some apps written in SubX and Mu, in 3 categories:
demonstrated there.
* `ex*`: small stand-alone examples that don't need any of the shared code at
the top-level. They each have a simple pedagogical goal. Try these first.
* Code unique to phases of our build toolchain:
* Core SubX: `hex`, `survey`, `pack`, `dquotes`, `assort`, `tests`
* Syntax sugar for SubX: `sigils`, `calls`, `braces`
* More ambitious translator for a memory-safe language (in progress): `mu`
* Miscellaneous test programs.

9
edit
View File

@ -12,12 +12,7 @@ fi
if [[ $EDITOR == *'vim'* ]] if [[ $EDITOR == *'vim'* ]]
then then
LOCAL_SETTINGS='-S vimrc.vim' $EDITOR -S vimrc.vim apps/$1.subx
fi
if [[ $1 == 'ex'* ]]
then
eval $EDITOR $LOCAL_SETTINGS examples/$1.subx
else else
eval $EDITOR $LOCAL_SETTINGS apps/$1.subx $EDITOR apps/$1.subx
fi fi

View File

@ -1,6 +0,0 @@
Small example programs, each with a simple pedagogical goal.
They also help to validate SubX instruction semantics against native x86
hardware. For example, loading a single byte to a register would for some time
clear the rest of the register. This behavior was internally consistent with
unit tests. It took running an example binary natively to catch the discrepancy.

104
test_apps
View File

@ -28,144 +28,144 @@ echo "== translating and running using C++"
# example programs # example programs
echo ex1 echo ex1
./subx translate init.$OS examples/ex1.subx -o examples/ex1 ./subx translate init.$OS apps/ex1.subx -o apps/ex1
test "$1" = 'record' || git diff --exit-code examples/ex1 test "$1" = 'record' || git diff --exit-code apps/ex1
test $EMULATED && { test $EMULATED && {
./subx run examples/ex1 || ret=$? ./subx run apps/ex1 || ret=$?
test $ret -eq 42 # life, the universe and everything test $ret -eq 42 # life, the universe and everything
} }
test $NATIVE && { test $NATIVE && {
examples/ex1 || ret=$? apps/ex1 || ret=$?
test $ret -eq 42 # life, the universe and everything test $ret -eq 42 # life, the universe and everything
} }
echo ex2 echo ex2
./subx translate init.$OS examples/ex2.subx -o examples/ex2 ./subx translate init.$OS apps/ex2.subx -o apps/ex2
test "$1" = 'record' || git diff --exit-code examples/ex2 test "$1" = 'record' || git diff --exit-code apps/ex2
test $EMULATED && { test $EMULATED && {
./subx run examples/ex2 || ret=$? ./subx run apps/ex2 || ret=$?
test $ret -eq 2 # 1 + 1 test $ret -eq 2 # 1 + 1
} }
test $NATIVE && { test $NATIVE && {
examples/ex2 || ret=$? apps/ex2 || ret=$?
test $ret -eq 2 # 1 + 1 test $ret -eq 2 # 1 + 1
} }
echo ex3 echo ex3
./subx translate init.$OS examples/ex3.subx -o examples/ex3 ./subx translate init.$OS apps/ex3.subx -o apps/ex3
test "$1" = 'record' || git diff --exit-code examples/ex3 test "$1" = 'record' || git diff --exit-code apps/ex3
test $EMULATED && { test $EMULATED && {
./subx run examples/ex3 || ret=$? ./subx run apps/ex3 || ret=$?
test $ret -eq 55 # 1 + 2 + ... + 10 test $ret -eq 55 # 1 + 2 + ... + 10
} }
test $NATIVE && { test $NATIVE && {
examples/ex3 || ret=$? apps/ex3 || ret=$?
test $ret -eq 55 # 1 + 2 + ... + 10 test $ret -eq 55 # 1 + 2 + ... + 10
} }
echo ex4 echo ex4
./subx translate init.$OS examples/ex4.subx -o examples/ex4 ./subx translate init.$OS apps/ex4.subx -o apps/ex4
test "$1" = 'record' || git diff --exit-code examples/ex4 test "$1" = 'record' || git diff --exit-code apps/ex4
test $EMULATED && { test $EMULATED && {
echo a | ./subx run examples/ex4 >ex4.out || true echo a | ./subx run apps/ex4 >ex4.out || true
test `cat ex4.out` = 'a' test `cat ex4.out` = 'a'
} }
test $NATIVE && { test $NATIVE && {
echo a | examples/ex4 >ex4.out || true echo a | apps/ex4 >ex4.out || true
test `cat ex4.out` = 'a' test `cat ex4.out` = 'a'
} }
echo ex5 echo ex5
./subx translate init.$OS examples/ex5.subx -o examples/ex5 ./subx translate init.$OS apps/ex5.subx -o apps/ex5
test "$1" = 'record' || git diff --exit-code examples/ex5 test "$1" = 'record' || git diff --exit-code apps/ex5
test $EMULATED && { test $EMULATED && {
echo a | ./subx run examples/ex5 >ex5.out || true echo a | ./subx run apps/ex5 >ex5.out || true
test `cat ex5.out` = 'a' test `cat ex5.out` = 'a'
} }
test $NATIVE && { test $NATIVE && {
echo a | examples/ex5 >ex5.out || true echo a | apps/ex5 >ex5.out || true
test `cat ex5.out` = 'a' test `cat ex5.out` = 'a'
} }
echo ex6 echo ex6
./subx translate init.$OS examples/ex6.subx -o examples/ex6 ./subx translate init.$OS apps/ex6.subx -o apps/ex6
test "$1" = 'record' || git diff --exit-code examples/ex6 test "$1" = 'record' || git diff --exit-code apps/ex6
test $EMULATED && { test $EMULATED && {
./subx run examples/ex6 >ex6.out || true ./subx run apps/ex6 >ex6.out || true
test "`cat ex6.out`" = 'Hello, world!' test "`cat ex6.out`" = 'Hello, world!'
} }
test $NATIVE && { test $NATIVE && {
examples/ex6 >ex6.out || true apps/ex6 >ex6.out || true
test "`cat ex6.out`" = 'Hello, world!' test "`cat ex6.out`" = 'Hello, world!'
} }
echo ex7 echo ex7
./subx translate init.$OS examples/ex7.subx -o examples/ex7 ./subx translate init.$OS apps/ex7.subx -o apps/ex7
test "$1" = 'record' || git diff --exit-code examples/ex7 test "$1" = 'record' || git diff --exit-code apps/ex7
test $EMULATED && { test $EMULATED && {
./subx run examples/ex7 || ret=$? ./subx run apps/ex7 || ret=$?
test $ret -eq 97 # 'a' test $ret -eq 97 # 'a'
} }
test $NATIVE && { test $NATIVE && {
examples/ex7 || ret=$? apps/ex7 || ret=$?
test $ret -eq 97 # 'a' test $ret -eq 97 # 'a'
} }
echo ex8 echo ex8
./subx translate init.$OS examples/ex8.subx -o examples/ex8 ./subx translate init.$OS apps/ex8.subx -o apps/ex8
test "$1" = 'record' || git diff --exit-code examples/ex8 test "$1" = 'record' || git diff --exit-code apps/ex8
test $EMULATED && { test $EMULATED && {
./subx run examples/ex8 abcd || ret=$? ./subx run apps/ex8 abcd || ret=$?
test $ret -eq 4 # length('abcd') test $ret -eq 4 # length('abcd')
} }
test $NATIVE && { test $NATIVE && {
examples/ex8 abcd || ret=$? apps/ex8 abcd || ret=$?
test $ret -eq 4 # length('abcd') test $ret -eq 4 # length('abcd')
} }
echo ex9 echo ex9
./subx translate init.$OS examples/ex9.subx -o examples/ex9 ./subx translate init.$OS apps/ex9.subx -o apps/ex9
test "$1" = 'record' || git diff --exit-code examples/ex9 test "$1" = 'record' || git diff --exit-code apps/ex9
test $EMULATED && { test $EMULATED && {
./subx run examples/ex9 z x || ret=$? ./subx run apps/ex9 z x || ret=$?
test $ret -eq 2 # 'z' - 'x' test $ret -eq 2 # 'z' - 'x'
} }
test $NATIVE && { test $NATIVE && {
examples/ex9 z x || ret=$? apps/ex9 z x || ret=$?
test $ret -eq 2 # 'z' - 'x' test $ret -eq 2 # 'z' - 'x'
} }
echo ex10 echo ex10
./subx translate init.$OS examples/ex10.subx -o examples/ex10 ./subx translate init.$OS apps/ex10.subx -o apps/ex10
test "$1" = 'record' || git diff --exit-code examples/ex10 test "$1" = 'record' || git diff --exit-code apps/ex10
test $EMULATED && { test $EMULATED && {
./subx run examples/ex10 abc abc || ret=$? ./subx run apps/ex10 abc abc || ret=$?
test $ret -eq 1 # equal test $ret -eq 1 # equal
./subx run examples/ex10 abc abcd # 0; not equal ./subx run apps/ex10 abc abcd # 0; not equal
} }
test $NATIVE && { test $NATIVE && {
examples/ex10 abc abc || ret=$? apps/ex10 abc abc || ret=$?
test $ret -eq 1 # equal test $ret -eq 1 # equal
examples/ex10 abc abcd # 0; not equal apps/ex10 abc abcd # 0; not equal
} }
echo ex11 echo ex11
./subx translate init.$OS examples/ex11.subx -o examples/ex11 ./subx translate init.$OS apps/ex11.subx -o apps/ex11
test "$1" = 'record' || git diff --exit-code examples/ex11 test "$1" = 'record' || git diff --exit-code apps/ex11
test $EMULATED && { test $EMULATED && {
./subx run examples/ex11 ./subx run apps/ex11
echo echo
} }
test $NATIVE && { test $NATIVE && {
examples/ex11 apps/ex11
echo echo
} }
echo ex12 echo ex12
./subx translate init.$OS examples/ex12.subx -o examples/ex12 ./subx translate init.$OS apps/ex12.subx -o apps/ex12
test "$1" = 'record' || git diff --exit-code examples/ex12 test "$1" = 'record' || git diff --exit-code apps/ex12
test $EMULATED && ./subx run examples/ex12 # final byte of mmap'd address is well-nigh guaranteed to be 0 test $EMULATED && ./subx run apps/ex12 # final byte of mmap'd address is well-nigh guaranteed to be 0
test $NATIVE && examples/ex12 test $NATIVE && apps/ex12
# Larger apps that use the standard library. # Larger apps that use the standard library.
@ -304,8 +304,8 @@ echo "== translating using SubX (native only)"
for n in `seq 1 12` for n in `seq 1 12`
do do
echo ex$n echo ex$n
./translate_subx init.$OS examples/ex$n.subx ./translate_subx init.$OS apps/ex$n.subx
diff examples/ex$n a.elf diff apps/ex$n a.elf
done done
# Larger apps that use the standard library. # Larger apps that use the standard library.

View File

@ -44,15 +44,7 @@ else
endif endif
function! EditSubx(cmd, arg) function! EditSubx(cmd, arg)
exec "silent! " . a:cmd . " " . SubxPath(a:arg) exec "silent! " . a:cmd . " apps/" . a:arg . ".subx"
endfunction
function! SubxPath(arg)
if a:arg =~ "^ex"
return "examples/" . a:arg . ".subx"
else
return "apps/" . a:arg . ".subx"
endif
endfunction endfunction
" we often want to crib lines of machine code from other files " we often want to crib lines of machine code from other files