From ac6cc6b2405bb6d3775344a873fb1172f38f1c7e Mon Sep 17 00:00:00 2001 From: P. J. McDermott Date: Sat, 20 Feb 2016 12:23:16 -0500 Subject: Implement command substitution (warning: ugly and broken) --- (limited to 'parsing') diff --git a/parsing/lexer.sh b/parsing/lexer.sh index b03878d..1e9b2e0 100644 --- a/parsing/lexer.sh +++ b/parsing/lexer.sh @@ -276,6 +276,7 @@ scan_wordexp() local res= local param= local word= + local toks= wordexp='' ln_off=0 @@ -398,8 +399,30 @@ scan_wordexp() ;; *) # Command substitution - synerr 'Command substitution is %s' \ - 'not yet supported' + if ! res="$(parse_sub "${fname}" \ + ${lineno} "${c}" false)" + then + exit 1 + fi + ln_off=${res%%${RS}*} + res="${res#*${RS}}" + c="${res%%${RS}*}" + res="${res#*${RS}}" + toks="${res%%${RS}*}" + lineno=${ln_off} + wordexp="\$(${STX}${toks}${ETX}" + # Get ")" + case "${c}" in + ')') + wordexp="${wordexp}${c}" + pgetc + ;; + *) + echo "c: '$c'" >&2 + echo "wordexp: $wordexp" >&2 + synerr 'Missing ")"' + ;; + esac ;; esac ;; @@ -600,15 +623,35 @@ init_lexer() { local fn="${1}" local ln="${2}" - shift 2 + local char="${3}" + shift 3 fname="${fn}" lineno=${ln} tokens='' - pgetc + case "${char}" in + '') + pgetc + ;; + *) + c="${char}" + ;; + esac next } +get_lineno() +{ + printf '%d' ${lineno} + return 0 +} + +get_lexer_char() +{ + printf '%c' "${c}" + return 0 +} + get_tokens() { printf '%s' "${tokens}" diff --git a/parsing/parse.sh b/parsing/parse.sh index a28aad2..4d4b9ea 100644 --- a/parsing/parse.sh +++ b/parsing/parse.sh @@ -583,20 +583,28 @@ sequential_sep() return 1 } +# Maybe parse() should just tell the lexer what the starting production (parser +# entry point) is. parse_sub() { local fn="${1}" local ln="${2}" - shift 2 + local lexer_char="${3}" + local complete="${4}" + shift 3 - init_lexer "${fn}" ${ln} + init_lexer "${fn}" ${ln} "${lexer_char}" # If this returns (does not exit), there are no errors. complete_command - if ! accept T_EOF; then + if ${complete} && ! accept T_EOF; then synexp '' fi + get_lineno + printf '%c' "${RS}" + get_lexer_char + printf '%c' "${RS}" get_tokens return 0 @@ -606,8 +614,10 @@ parse() { local fn="${1}" shift 1 + local toks= - if parse_sub "${fn}" 1; then + if toks="$(parse_sub "${fn}" 1 '' true)"; then + printf '%s\n' "${toks#*${RS}*${RS}}" return 0 fi return 1 @@ -640,7 +650,7 @@ try() } #try '"foo bar" && $baz || qux' '${quux%uux quuux' -try '"foo bar" && $baz || qux' '${quux%uux } quuux' +#try '"foo bar" && $baz || qux' '${quux%uux } quuux' #try 'foo ${bar}' #try 'foo ${#bar}' #try 'foo ${bar#baz}' @@ -659,5 +669,5 @@ try '"foo bar" && $baz || qux' '${quux%uux } quuux' #try 'foo(){ bar; }' #try 'case foo in bar) baz;; (qux) quux;; quux);; esac' #try 'foo bar ( baz )' -#try 'foo $(bar)' +try 'foo $(bar)' #try 'foo $((1 + 1))' -- cgit v0.9.1