HT="$(printf '\t.')"; HT="${HT%.}" LF="$(printf '\n.')"; LF="${LF%.}" RS="$(printf '\036.')"; RS="${RS%.}" US="$(printf '\037.')"; US="${US%.}" . ./tokens.sh . ./lexer.sh complete_command() { if list; then separator return 0 fi return 1 } list() { if and_or; then while separator_op; do if ! and_or; then return 1 fi done return 0 fi return 1 } and_or() { if pipeline; then while accept T_AND_IF || accept T_OR_IF; do if ! linebreak || ! pipeline; then return 1 fi done return 0 fi return 1 } pipeline() { accept T_BANG if pipe_sequence; then return 0 fi return 1 } pipe_sequence() { if command; then while accept T_PIPE; do if ! linebreak || ! command; then return 1 fi done return 0 fi return 1 } command() { # XXX: Unfinished accept T_WORD } 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 } parse() { local fn="${1}" shift 1 init_lexer "${fn}" while complete_command; do :; done if :; then # TODO: Test for EOF or errors get_tokens return 0 fi return 1 } if tokens="$(printf '%s\n' '"foo bar" && $baz || qux' '${quux%uux } quuux' | \ parse -)"; then IFS="${RS}" for t in ${tokens}; do printf 'Token: %s\n' "$(tokname "${t}")" case "${t%${US}*}" in T_WORD) printf ' "%s"\n' "${t#T_WORD${US}}" ;; esac done unset IFS else echo FAIL fi