Compilers

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.WP20160615

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.
-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 to load, include, and call respectively, but in a multi-file manner.
  • loader_addpath (or addpath 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 (or resetloader in deprecated mode) – Compiler does nothing and line is not included to compiled file.
  • loader_finish (or finishloader 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:

#!/bin/sh

#begin_skip_block
. ./loader.sh
#end_skip_block

loader_addpath source

include some_dependency.sh  # Loads source/some_dependency.sh.

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

Next Page: Downloads