diff options
Diffstat (limited to 'eshtrans/frontend/parser.esh')
-rw-r--r-- | eshtrans/frontend/parser.esh | 591 |
1 files changed, 591 insertions, 0 deletions
diff --git a/eshtrans/frontend/parser.esh b/eshtrans/frontend/parser.esh new file mode 100644 index 0000000..d49fa77 --- /dev/null +++ b/eshtrans/frontend/parser.esh @@ -0,0 +1,591 @@ +# Eggshell parser +# +# 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 +# <http://www.gnu.org/licenses/>. + +ptrace=false + +# +# Function tracing +# + +ptrace_begn() +{ + local fn="${1}" + shift 1 + + if ${ptrace}; then + printf 'TRACE: BEGN %s()\n' "${fn}" >&2 + fi +} + +ptrace_pass() +{ + local fn="${1}" + shift 1 + + if ${ptrace}; then + printf 'TRACE: PASS %s()\n' "${fn}" >&2 + fi +} + +ptrace_fail() +{ + local fn="${1}" + shift 1 + + if ${ptrace}; then + printf 'TRACE: FAIL %s()\n' "${fn}" >&2 + fi +} + +# +# Parser +# + +complete_command() +{ + if list; then + separator + return 0 + fi + return 1 +} + +list() +{ + ptrace_begn list + if and_or; then + while separator && and_or; do + : + done + ptrace_pass list + return 0 + fi + ptrace_fail list + return 1 +} + +and_or() +{ + ptrace_begn and_or + if pipeline; then + while accept T_AND_IF || accept T_OR_IF; do + if ! linebreak || ! pipeline; then + ptrace_fail and_or + return 1 + fi + done + ptrace_pass and_or + return 0 + fi + ptrace_fail and_or + return 1 +} + +pipeline() +{ + ptrace_begn pipeline + accept T_BANG + if pipe_sequence; then + ptrace_pass pipeline + return 0 + fi + ptrace_fail pipeline + return 1 +} + +pipe_sequence() +{ + ptrace_begn pipe_sequence + if command; then + while accept T_PIPE; do + if ! linebreak || ! command; then + ptrace_fail pipe_sequence + return 1 + fi + done + ptrace_pass pipe_sequence + return 0 + fi + ptrace_fail pipe_sequence + return 1 +} + +command() +{ + ptrace_begn command + if simple_command; then + ptrace_pass command + return 0 + elif compound_command; then + redirect_list + ptrace_pass command + return 0 + fi + ptrace_fail command + return 1 +} + +compound_command() +{ + ptrace_begn compound_command + if brace_group; then + ptrace_pass compound_command + return 0 + elif subshell; then + ptrace_pass compound_command + return 0 + elif for_clause; then + ptrace_pass compound_command + return 0 + elif case_clause; then + ptrace_pass compound_command + return 0 + elif if_clause; then + ptrace_pass compound_command + return 0 + elif while_clause; then + ptrace_pass compound_command + return 0 + elif until_clause; then + ptrace_pass compound_command + return 0 + fi + ptrace_fail compound_command + return 1 +} + +subshell() +{ + ptrace_begn subshell + if accept T_LPAREN && compound_list && expect T_RPAREN; then + ptrace_pass subshell + return 0 + fi + ptrace_fail subshell + return 1 +} + +compound_list() +{ + ptrace_begn compound_list + newline_list + if term; then + separator + ptrace_pass compound_list + return 0 + fi + ptrace_fail compound_list + return 1 +} + +term() +{ + ptrace_begn term + if and_or; then + while separator; do + and_or + done + ptrace_pass term + return 0 + fi + ptrace_fail term + return 1 +} + +for_clause() +{ + ptrace_begn for_clause + if accept T_FOR; then + if expect T_NAME && linebreak; then + if accept T_IN; then + wordlist + if ! sequential_sep; then + ptrace_fail for_clause + return 1 + fi + fi + if do_group; then + ptrace_pass for_clause + return 0 + fi + fi + fi + ptrace_fail for_clause + return 1 +} + +wordlist() +{ + ptrace_begn wordlist + if accept T_WORD; then + while accept T_WORD; do :; done + ptrace_pass wordlist + return 0 + fi + ptrace_fail wordlist + return 1 +} + +case_clause() +{ + if accept T_CASE; then + if expect T_WORD && linebreak && expect T_IN && linebreak; then + case_list || case_list_ns + expect T_ESAC + return 0 + fi + fi + return 1 +} + +case_list_ns() +{ + if case_list && case_item_ns; then + return 0 + elif case_item_ns; then + return 0 + fi + return 1 +} + +case_list() +{ + if case_item; then + while case_item; do + : + done + return 0 + fi + return 1 +} + +case_item_ns() +{ + accept T_LPAREN + if pattern && expect RPAREN; then + compound_list + if linebreak; then + return 0 + fi + fi + return 1 +} + +case_item() +{ + accept T_LPAREN + if pattern && expect T_RPAREN; then + if compound_list || linebreak; then + if expect T_DSEMI && linebreak; then + return 0 + fi + fi + fi + return 1 +} + +pattern() +{ + if accept T_CMDNAME; then + while accept T_PIPE; do + expect T_WORD + done + return 0 + fi + return 1 +} + +if_clause() +{ + if accept T_IF; then + if compound_list && expect T_THEN && compound_list; then + else_part + expect T_FI + return 0 + fi + fi + return 1 +} + +else_part() +{ + while accept T_ELIF; do + if compound_list && expect T_THEN && compound_list; then + continue + fi + return 1 + done + if accept T_ELSE; then + if compound_list; then + return 0 + fi + fi + return 1 +} + +while_clause() +{ + if accept T_WHILE; then + if compound_list && do_group; then + return 0 + fi + fi + return 1 +} + +until_clause() +{ + if accept T_UNTIL; then + if compound_list && do_group; then + return 0 + fi + fi + return 1 +} + +function_body() +{ + ptrace_begn function_body + if compound_command; then + redirect_list + ptrace_pass function_body + return 0 + fi + ptrace_fail function_body + return 1 +} + +brace_group() +{ + ptrace_begn brace_group + if accept T_LBRACE && compound_list && expect T_RBRACE; then + ptrace_pass brace_group + return 0 + fi + ptrace_fail brace_group + return 1 +} + +do_group() +{ + ptrace_begn do_group + if accept T_DO && compound_list && expect T_DONE; then + ptrace_pass do_group + return 0 + fi + ptrace_fail do_group + return 1 +} + +simple_command() +{ + ptrace_begn simple_command + if cmd_prefix; then + if cmd_word; then + cmd_suffix + fi + ptrace_pass simple_command + return 0 + elif accept T_FNAME; then + if accept T_LPAREN; then + expect T_RPAREN + if linebreak && function_body; then + ptrace_pass simple_command + return 0 + fi + else + cmd_suffix + ptrace_pass simple_command + return 0 + fi + elif cmd_name; then + cmd_suffix + ptrace_pass simple_command + return 0 + fi + ptrace_fail simple_command + return 1 +} + +cmd_name() +{ + ptrace_begn cmd_name + # TODO: Assignment + if accept T_CMDNAME; then + ptrace_pass cmd_name + return 0 + fi + ptrace_fail cmd_name + return 1 +} + +cmd_word() +{ + ptrace_begn cmd_word + # TODO: Assignment + if accept T_WORD; then + ptrace_pass cmd_word + return 0 + fi + ptrace_fail cmd_word + return 1 +} + +cmd_prefix() +{ + ptrace_begn cmd_prefix + if io_redirect || accept T_ASSIGNMENT_WORD; then + while io_redirect || accept T_ASSIGNMENT_WORD; do + : + done + ptrace_pass cmd_prefix + return 0 + fi + ptrace_fail cmd_prefix + return 1 +} + +cmd_suffix() +{ + ptrace_begn cmd_suffix + if io_redirect || accept T_WORD; then + while io_redirect || accept T_WORD; do + : + done + ptrace_pass cmd_suffix + return 0 + fi + ptrace_fail cmd_suffix + return 1 +} + +redirect_list() +{ + ptrace_begn redirect_list + if io_redirect; then + while io_redirect; do + : + done + ptrace_pass redirect_list + return 0 + fi + ptrace_fail redirect_list + return 1 +} + +io_redirect() +{ + ptrace_begn io_redirect + if io_file || io_here; then + ptrace_pass io_redirect + return 0 + fi + ptrace_fail io_redirect + return 1 +} + +io_file() +{ + if accept T_LESS || accept T_LESSAND || accept T_GREAT || \ + accept T_GREATAND || accept T_DGREAT || \ + accept T_LESSGREAT || accept T_CLOBBER; then + if filename; then + return 0 + fi + fi + return 1 +} + +filename() +{ + if accept T_WORD; then + return 0 + fi + return 1 +} + +io_here() +{ + if accept T_DLESS || accept T_DLESSDASH; then + if here_end; then + return 0 + fi + fi + return 1 +} + +here_end() +{ + if accept T_WORD; then + return 0 + fi + return 1 +} + +newline_list() +{ + if accept T_NEWLINE; then + while accept T_NEWLINE; do + : + done + return 0 + fi + return 1 +} + +linebreak() +{ + newline_list + return 0 +} + +separator_op() +{ + if accept T_AND || accept T_SEMI; then + return 0 + fi + return 1 +} + +separator() +{ + if separator_op && linebreak; then + return 0 + elif newline_list; then + return 0 + fi + return 1 +} + +sequential_sep() +{ + ptrace_begn sequential_sep + if accept T_SEMI; then + if linebreak; then + ptrace_pass sequential_sep + return 0 + fi + elif newline_list; then + ptrace_pass sequential_sep + return 0 + fi + ptrace_fail sequential_sep + return 1 +} |