Shell Script Loader has also been designed so that applications that were built with it can be compiled by an external compiler to form a single file out of the many files that compose them.
A Compiler Written in Awk
Currently a line-based compiler that’s written in GNU Awk (gawk
) is already available. It can also be downloaded in SourceForge. The compiler still has difficult limitations with imitating functions of call()
but with common usage it should be more than enough.
There’s also a plan to make a compiler in a different language or parser like Ruby or Perl but that would take time.
This is the output of gawk -f compiler.gawk -- --help
:
Prototype compiler for shell scripts based on Shell Script Loader
Version: 0.1.1
Usage Summary: compiler.gawk [option [optarg] [option2] ...] file [file2 ...]
Options:
-a, --addpath path Add a path to the search list.
--debug Enable debug mode.
--deprecated Deprecated mode. Parse deprecated functions instead.
-f, --find path Specifies the location of the 'find' utility.
By default, it is the output of 'which find', or simply
"find". This is only useful with --extended.
-h, --help|--usage Show this message.
-H, --header file Insert a file at the top of the compiled form. This can
be used to insert program description and license info.
-ia, --ignore-addpaths Ignore embedded addpath commands in scripts.
-ir, --ignore-resets Ignore embedded reset commands in scripts.
-n, --no-info Do not add informative comments.
-ni, --no-indent Do not add extra alignment indents to contents when
compiling.
-o, --output file Use file for output instead of stdout.
-O Optimize. (enables --strip-all-safe, and --no-info)
--RS0 Parse commands based on RS0 (default).
--RS0X Parse commands based on RS0X (--extended).
--RS0L Parse commands based on RS0L (--deprecated).
--RS0S Parse commands based on RS0S (--deprecated + --extended).
--sed Use sed by default in some operations like stripping.
-s, --shell path Includes a '#!<path>' header to the output.
--strip-bl Strip all blank lines.
--strip-c Strip comments from code. (safe)
--strip-ebl Strip extra blank lines. (safe)
--strip-ls Strip leading spaces in every line of the code.
--strip-tc Strip trailing comments. (not really implemented yet)
--strip-ts Strip trailing spaces in every line of the code. (safe)
--strip-all Do all the strip methods mentioned above.
--strip-all-safe Do all the safe strip methods mentioned above.
--tempdir path Use a different directory for temporary files.
-x, --extended Parse extended functions loadx(), includex() and callx().
-V, --version Show version.
To compile a set of scripts, you simply have to use the main file as a target, and add paths where the shell scripts that would be called would be searched.
Here’s an example command using the GNU Awk based compiler to compile PlayShell:
gawk -f loader/compiler.gawk -- \
-a ./source -s /bin/bash -H playshell.header \
-O -o playshell source/playshell.sh
And this is the list of directives that the compiler recognizes:
load
– Compiler processes argument file and unconditionally includes to the compiled file.include
– Compiler processes argument file and includes it to the compiled file if it hasn’t been included yet.call
– Compiler wraps file to a function and adds a call to that function in a subshell. The file is wrapped only once based on form of its path.loadx
,includex
,callx
– Compiler does something similar toload
,include
, andcall
respectively, but in a multi-file manner.loader_addpath
(oraddpath
in deprecated mode) – Compiler tries to parse the argument as a path and add it to search list.loader_flag
– Compiler does nothing and line is not included to compiled file.loader_reset
(orresetloader
in deprecated mode) – Compiler does nothing and line is not included to compiled file.loader_finish
(orfinishloader
in deprecated mode) – Compiler does nothing and line is not included to compiled file.
Since the compiler is line-based, it could only recognize directives in the scope of a line, and it cannot detect whether it is part of a comment, a multi-line string, or a here document.
To avoid lines from being unintentionally parsed, you can place directives around them. These directives look like comments, and are recognized by the compiler. It comes in pairs; one starts the beginning of the block, and the other the end of the block.
-
#begin_skip_block
-#end_skip_block
or
#begin_compiler_skip
-#end_compiler_skip
Specifies that text will not be included to the compiled file.
-
#begin_no_parse_block
-#end_no_parse_block
or
#begin_compiler_no_parse
-#end_compiler_no_parse
Specifies that text will be included but not parsed or will just be treated as plain text.
This also prevents lines beginning with
#
from being removed when comment stripping (--strip-c
) is enabled. -
#begin_no_indent_block
-#end_no_indent_block
or
#begin_compiler_no_indent
-#end_compiler_no_indent
Specifies that text will not be indented when included inside call functions.
Here’s an example for a script that can both be compiled and run manually:
This one shows an example to a concept where we don’t want some lines to be parsed or removed in a here document:
#begin_no_parse_block
cat <<EOF
Don't
load or
include anything.
# Don't remove lines
# that look like comments too.
EOF
#end_no_parse_block