Code is to match '(' with ')' and '{' with '}'. My problem is that the way I did is request to pop() is creating subshell. Is there a way to modify it with locale -n or some new features from bash 4.3> ?
#!/bin/bash
set -x
top=0
STACK_SIZE=4
declare -a contents
read -rp "Enter parentheses: " input
if [ -z "$input" ]; then
echo "no input"
exit 1
fi
make_empty() {
top=0
}
is_empty() {
[ "$top" -eq 0 ] && return 0 || return 1
}
is_full() {
[ "$top" -eq "$STACK_SIZE" ] && return 0 || return 1
}
push() {
if is_full; then
echo "Stack overflow"
exit 1
else
contents[$top]="$1"
((top++))
fi
}
pop() { #problematic function
if is_empty; then
echo "parentheses arent matched"
exit 1
else
((top--)) #this is the line that doesnt update $top var
echo "${contents[$top]}" #but updates local copy of top inside its subshell
fi
}
i=${#input}
while read -n 1 char; do
case $char in
} | { | \( | \));;
*) echo "wrong input"
exit 1;;
esac
((i--))
if [ "$char" == '(' ] || [ "$char" == "{" ]; then
push "$char"
elif [ "$char" == ')' ] && [ "$(pop)" != '(' ]; then #here unintentional subshell creation
echo "not nested properly"
elif [ "$char" == '}' ] && [ "$(pop)" != '{' ]; then #same here
echo "not nested properly"
elif [ "$i" -eq 0 ]; then
if is_empty; then
echo "matched"
break
else
echo "Not nested properly"
fi
fi
done <<<"$input"
input/output:
+ top=0
+ STACK_SIZE=4
+ declare -a contents
+ read -rp 'Enter parentheses: ' input
Enter parentheses: () #INPUT
+ '[' -z '()' ']'
+ i=2
+ read -n 1 char
+ case $char in
+ (( i-- ))
+ '[' '(' == '(' ']'
+ push '('
+ is_full
+ '[' 0 -eq 4 ']'
+ return 1
+ contents[$top]='('
+ (( top++ )) # TOP IS 1 NOW
+ read -n 1 char
+ case $char in
+ (( i-- ))
+ '[' ')' == '(' ']'
+ '[' ')' == '{' ']'
+ '[' ')' == ')' ']'
++ pop
++ is_empty
++ '[' 1 -eq 0 ']'
++ return 1
++ (( top-- )) #TOP SHOULD BE 0 AFTER THIS
++ echo '('
+ '[' '(' '!=' '(' ']'
+ '[' ')' == '}' ']'
+ '[' 0 -eq 0 ']'
+ is_empty
+ '[' 1 -eq 0 ']' #TOP IS NOT UPDATED HERE
+ return 1
+ echo 'Not nested properly'
Not nested properly
+ read -n 1 char
+ case $char in
+ echo 'wrong input'
wrong input
+ exit 1
I commented the code to pinpoint the lines where the problem is. I solved the problem by rewriting the code from scratch but would like to see if its possible to do something with this subshell creation.
Working UPDATED CODE:
#set -x
top=0
STACK_SIZE=4
declare -a contents
read -rp "Enter parentheses: " input
if [ -z "$input" ]; then
echo "no input"
exit 1
fi
make_empty() {
top=0
}
is_empty() {
[ "$top" -eq 0 ] && return 0 || return 1
}
is_full() {
[ "$top" -eq "$STACK_SIZE" ] && return 0 || return 1
}
push() {
if is_full; then
echo "Stack overflow"
exit 1
else
contents[$top]="$1"
((top++))
fi
}
pop() {
if is_empty; then
echo "Parentheses aren't matched"
exit 1
else
((top--))
fi
}
i=0
while [ "$i" -lt "${#input}" ]; do
char="${input:$i:1}"
if [ "$char" == '(' ] || [ "$char" == '{' ]; then
push "$char"
elif [ "$char" == ')' ]; then
if [ "$top" -eq 0 ] || [ \
"${contents[$((top-1))]}" != '(' ]; then
echo "not nested properly"
exit 1
else
pop
fi
elif [ "$char" == '}' ]; then
if [ "$top" -eq 0 ] || [ \
"${contents[$((top-1))]}" != '{' ]; then
echo "not nested properly"
exit 1
else
pop
fi
else
echo "wrong input"
exit 1
fi
((i++))
done
is_empty && echo "matched" || echo "Not nested properly"
No.
The only way is to implement inter-process communication, where the parent would listen for messages from child processes and act on them. This would be a lot of work.