summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eshld/Makefile3
-rw-r--r--eshld/eshrt.esh248
-rw-r--r--eshld/link.esh28
-rw-r--r--eshld/main.esh2
4 files changed, 257 insertions, 24 deletions
diff --git a/eshld/Makefile b/eshld/Makefile
index 03b3c3b..a768ca6 100644
--- a/eshld/Makefile
+++ b/eshld/Makefile
@@ -1,6 +1,7 @@
SOURCES = \
main.esh \
- link.esh
+ link.esh \
+ eshrt.esh
OBJECTS = $(SOURCES:.esh=.sh)
all: eshld
diff --git a/eshld/eshrt.esh b/eshld/eshrt.esh
new file mode 100644
index 0000000..0a6fdb7
--- /dev/null
+++ b/eshld/eshrt.esh
@@ -0,0 +1,248 @@
+# Eggshell Linker runtime library
+#
+# Copyright (C) 2016 Patrick "P. J." McDermott
+#
+# This file is part of the Eggshell Linker.
+#
+# The Eggshell Linker is free software: you can redistribute it
+# and/or modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, either version 3 of
+# the License, or (at your option) any later version.
+#
+# The Eggshell Linker is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with the Eggshell Linker If not, see
+# <http://www.gnu.org/licenses/>.
+
+eshrtbegin()
+{
+ cat <<-'EOF'
+__ESC="$(printf '\033.')"; __ESC="${__ESC%.}"
+ __RS="$(printf '\036.')"; __RS="${__RS%.}"
+ __US="$(printf '\037.')"; __US="${__US%.}"
+__fn_stack=''
+__fn_frame=''
+__fn_name=''
+__fn_tu=''
+__fn_vars=''
+__fn_var_vals=''
+__fn=''
+__prev_tu=''
+__prev_vars=''
+__var=''
+__val=''
+__init_funcs=''
+
+__fn_stack_push()
+{
+ __fn_stack="${__fn_stack}${__RS}${__fn_frame}"
+}
+
+__fn_stack_peek()
+{
+ __fn_frame="${__fn_stack##*${__RS}}"
+}
+
+__fn_stack_pop()
+{
+ __fn_stack_peek
+ __fn_stack="${__fn_stack%${__RS}*}"
+}
+
+__fn_frame_encode()
+{
+ # RS and US in frame variable values must be encoded.
+ __fn_var_vals="$(printf '%s' "${__fn_var_vals}" | sed "
+ s|${__ESC}|${__ESC}0|g;
+ s|${__RS}|${__ESC}1|g; s|${__US}|${__ESC}2|g;
+ ")"
+ __fn_frame="${__fn_name}${__US}${__fn_tu}"
+ __fn_frame="${__fn_frame}${__US}${__fn_vars}${__US}${__fn_var_vals}"
+}
+
+__fn_frame_decode()
+{
+ __fn_name="${__fn_frame%%${__US}*}"
+ __fn_frame="${__fn_frame#*${__US}}"
+ __fn_tu="${__fn_frame%%${__US}*}"
+ __fn_frame="${__fn_frame#*${__US}}"
+ __fn_vars="${__fn_frame%%${__US}*}"
+ __fn_var_vals="${__fn_frame#*${__US}}"
+ __fn_var_vals="$(printf '%s' "${__fn_var_vals}" | sed "
+ s|${__ESC}0|${__ESC}|g;
+ s|${__ESC}1|${__RS}|g; s|${__ESC}2|${__US}|g;
+ ")"
+}
+
+__fn_ctxsw()
+{
+ unset IFS
+ case "${__prev_tu}" in
+ ${__fn_tu});;
+ ?*)
+ # Unset static variables and functions from previous TU.
+ eval "unset \${__${__prev_tu}_static_vars}"
+ for __fn in $(eval printf '%s' \
+ "\"\${__${__prev_tu}_static_fns}\""); do
+ unset -f "${__fn%:*}"
+ done
+ ;; esac
+ case "${__fn_tu}" in
+ ${__prev_tu});;
+ ?*)
+ # Set static variables and function for the current TU.
+ eval "$(eval printf '%s' "\"$(eval printf '%s' \
+ "'\${__${__fn_tu}_static_var_vals}'")\"")"
+ for __fn in $(eval printf '%s' \
+ "\"\${__${__fn_tu}_static_fns}\""); do
+ eval "${__fn%:*}() { ${__fn#*:}; }"
+ done
+ ;; esac
+ unset ${__prev_vars}
+ eval "${__fn_var_vals}"
+}
+
+__fn_update_vars()
+{
+ for __var in ${__fn_vars}; do
+ __val="$(eval "printf '%s' \"\${${__var}}\"" | \
+ sed "s|'|'\\\\''|g;")"
+ __fn_var_vals="${__fn_var_vals} ${__var}='${__val}'"
+ done
+}
+
+__fn_start()
+{
+ # Old state.
+ __prev_tu="${__fn_tu}"
+ __prev_vars="${__fn_vars}"
+
+ # Update local vars in stack.
+ __fn_stack_pop
+ __fn_vars="${__prev_vars}"
+ __fn_update_vars
+ __fn_frame_encode
+ __fn_stack_push
+
+ # New state.
+ __fn_name="${2}"
+ __fn_tu="${1}"
+ __fn_vars=
+ __fn_var_vals=
+ __fn_frame_encode
+ __fn_stack_push
+
+ # Switch.
+ __fn_ctxsw
+}
+
+__fn_end()
+{
+ # Old state.
+ __fn_stack_pop
+ __fn_frame_decode
+ __prev_tu="${__fn_tu}"
+ __prev_vars="${__fn_vars}"
+
+ # New state.
+ __fn_stack_peek
+ __fn_frame_decode
+
+ # Switch.
+ __fn_ctxsw
+}
+
+__tu_end()
+{
+ # Save TU static vars.
+ for __var in $(eval "printf '%s' \"\${__${__tu}_static_vars}\""); do
+ __val="$(eval "printf '%s' \"\${${__var}}\"" | \
+ sed "s|'|'\\\\''|g")"
+ eval "__${__tu}_static_var_vals=\"\${__${__tu}_static_var_vals}\
+ ${__var}='\${__val}'\""
+ unset ${__var}
+ done
+
+ __tu=''
+}
+
+__stack_trace()
+{
+ IFS="${__RS}"
+ for __fn_frame in ${__fn_stack#${__RS}}; do
+ printf '%s\n' "${__fn_frame%%${__US}*}"
+ done
+}
+
+__local()
+{
+ for __var in "${@}"; do
+ case "${__var}" in
+ *=*)
+ __val="${__var#*=}"
+ __var="${__var%%=*}"
+ ;;
+ *)
+ __val=''
+ ;;
+ esac
+ case "${__var}" in [!A-Za-z_]* | *[!0-9A-Za-z_]*)
+ printf 'Syntax error: %s %s\n' \
+ 'illegal static variable name:' "${__var}" >&2
+ exit 1
+ ;; esac
+ eval "${__var}=\${__val}"
+ __fn_vars="${__fn_vars} ${__var}"
+ done
+}
+
+static()
+{
+ case "${__tu}" in '')
+ printf 'Error: Cannot declare static variables in functions' >&2
+ exit 1
+ ;; esac
+ for __var in "${@}"; do
+ case "${__var}" in
+ *=*)
+ __val="${__var#*=}"
+ __var="${__var%%=*}"
+ ;;
+ *)
+ __val=''
+ ;;
+ esac
+ case "${__var}" in [!A-Za-z_]* | *[!0-9A-Za-z_]*)
+ printf 'Syntax error: %s %s\n' \
+ 'illegal static variable name:' "${__var}" >&2
+ exit 1
+ ;; esac
+ eval "${__var}=\${__val}"
+ eval "__${__tu}_static_vars=\"\${__${__tu}_static_vars} \
+ ${__var}\""
+ done
+}
+
+__init()
+{
+ __init_funcs="${__init_funcs} ${1}"
+}
+EOF
+}
+
+eshrtend()
+{
+ local entry="${1}"
+ shift 1
+
+ cat <<-'EOF'
+for __func in ${__init_funcs}; do
+ ${__func}
+done
+EOF
+ printf '%s "${@}"\n' "${entry_point}"
+}
diff --git a/eshld/link.esh b/eshld/link.esh
index d01fc4d..d674821 100644
--- a/eshld/link.esh
+++ b/eshld/link.esh
@@ -1,6 +1,6 @@
-# Eggshell Linker entry point
+# Eggshell Linker program linking functions
#
-# Copyright (C) 2015 Patrick "P. J." McDermott
+# Copyright (C) 2015, 2016 Patrick "P. J." McDermott
#
# This file is part of the Eggshell Linker.
#
@@ -50,20 +50,11 @@ link_begin()
die 'Cannot open file "%s"' "${output}~"
fi
- # Write magic number and interpreter path.
+ # Add a magic number with interpreter path and the runtime library.
if ${make_executable}; then
printf '#!%s\n' "${interpreter}" >&3
+ eshrtbegin >&3
fi
-
- # Write __init() function.
- cat >&3 <<-'EOF'
- __init_funcs=''
- __init()
- {
- __init_funcs="${__init_funcs} ${1}"
- }
- EOF
-
}
link_file()
@@ -77,16 +68,9 @@ link_file()
link_end()
{
- # Add call to init functions.
- cat >&3 <<-'EOF'
- for __func in ${__init_funcs}; do
- ${__func}
- done
- EOF
-
- # Add call to entry point.
+ # Add calls to __init functions and the entry point.
if ${make_executable}; then
- printf '%s "${@}"\n' "${entry_point}" >&3
+ eshrtend "${entry_point}" >&3
fi
# Close output file, make it executable, and set its name.
diff --git a/eshld/main.esh b/eshld/main.esh
index 775179f..24cdae1 100644
--- a/eshld/main.esh
+++ b/eshld/main.esh
@@ -1,6 +1,6 @@
# Eggshell Linker entry point
#
-# Copyright (C) 2015 Patrick "P. J." McDermott
+# Copyright (C) 2015, 2016 Patrick "P. J." McDermott
#
# This file is part of the Eggshell Linker.
#