# Shell command language code generator
#
# Copyright (C) 2016 Patrick "P. J." McDermott
#
# This file is part of the Eggshell Compiler.
#
# The Eggshell Compiler 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 Compiler 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 Compiler. If not, see
# .
sc=
tu_id=
static_fn_n=
sgetc()
{
sc="$(dd bs=1 count=1 2>/dev/null; printf '.')"
sc="${sc%.}"
}
add_static_fn()
{
local fn="${1}"
printf '__%s_static_fns="${__%s_static_fns} %s:__%s_fn%d"\n' \
"${tu_id}" "${tu_id}" "${fn}" "${tu_id}" ${static_fn_n}
printf '__%s_fn%d' "${tu_id}" ${static_fn_n}
static_fn_n=$((${static_fn_n} + 1))
}
codegen_sub()
{
local array="${1}"
shift 1
local print_spc=
local ionum=
local fname=
local static=
local static_fname=
print_spc=false
ionum=false
fname=''
static=false
static_fname=false
IFS="${RS}"
for t in ${array}; do
if ${print_spc}; then
case "${t%${US}*}" in
T_NEWLINE)
;;
*)
printf ' '
;;
esac
print_spc=false
fi
# Handle I/O number false positives.
if ${ionum}; then
case "${t%${US}*}" in
T_WORD|T_CMDNAME|T_FNAME)
printf ' '
;;
esac
ionum=false
fi
# Function names
case "${t%${US}*}" in T_FNAME)
fname="${t}"
;;
esac
# State machine for static variables and functions
case "${t%${US}*}" in
T_STATIC)
static=true
continue
;;
esac
if ${static}; then
static=false
case "${t%${US}*}" in
T_FNAME)
static_fname=true
continue
;;
*)
toktext T_STATIC
printf ' '
;;
esac
elif ${static_fname}; then
static_fname=false
case "${t%${US}*}" in
T_LPAREN)
add_static_fn "${fname#*${US}}"
;;
*)
toktext T_STATIC
printf ' '
toktext "${fname}"
;;
esac
fi
# Function start/end tokens
case "${t%${US}*}" in
T_FN_START)
printf '__fn_start %s %s;' \
"${tu_id}" "${fname#*${US}}"
;;
T_FN_END)
printf '__fn_end;'
;;
T_RETURN)
printf '__fn_end; '
;;
esac
toktext "${t}"
case "${t%${US}*}" in
T_NEWLINE|T_LPAREN)
# Indenting lines can mess up here-documents.
# Adding a space after "(" can mess up function
# definitions (on zsh at least, while other
# shells accept the space).
;;
T_IO_NUMBER)
ionum=true
;;
*)
print_spc=true
;;
esac
done
unset IFS
}
# The token stack is encoded in a string in the following grammar:
# Terminal symbols:
# TOKEN
# Production rules:
# stack = tokens [ '' type '' stack '' [ tokens ] ] ;
# tokens = TOKEN { '' TOKEN } ;
# type = 'C' ;
# We need to recurse through this stack to get to all the tokens.
# Each element in the stack (an array of tokens) gets run through the codegen to
# become text that is inserted into the array below.
sh_parse_stack()
{
local array=
array=''
while :; do
sgetc
case "${sc}" in
'')
# EOF
break
;;
"${SOH}")
# New stack element
sgetc
case "${sc}" in
'C')
# Command substitution
sgetc # STX
array="${array}$(\
sh_parse_stack)."
array="${array%.}"
;;
esac
;;
"${ETX}")
# End of stack element
break
;;
*)
# Token character
array="${array}${sc}"
;;
esac
done
codegen_sub "${array}"
}
sh_set_tu_id()
{
local toks="${1}"
tu_id="$(printf '%s' "${toks}" | sha256sum -)"
tu_id="${tu_id% -}"
return 0
}
sh_start_tu()
{
printf '__tu=%s\n' "${tu_id}"
printf '__%s_static_vars=\n' "${tu_id}"
printf '__%s_static_var_vals=\n' "${tu_id}"
printf '__%s_static_fns=\n' "${tu_id}"
static_fn_n=0
}
sh_end_tu()
{
printf '__tu_end\n'
}