summaryrefslogtreecommitdiffstats
path: root/eshtrans/frontend/parser.esh
diff options
context:
space:
mode:
Diffstat (limited to 'eshtrans/frontend/parser.esh')
-rw-r--r--eshtrans/frontend/parser.esh591
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
+}