Skip to content

Instantly share code, notes, and snippets.

@dolik-rce
Created February 19, 2021 11:08
Show Gist options
  • Save dolik-rce/c14e6b85cec2a6a686c252c213ff7ebb to your computer and use it in GitHub Desktop.
Save dolik-rce/c14e6b85cec2a6a686c252c213ff7ebb to your computer and use it in GitHub Desktop.
Peg grammar optimizer
#!/bin/bash
# Usage: optimizer.sh [-v] <file.peg>
set -e
dbg() {
if [ "$VERBOSE" ]; then
echo "$1" > /dev/stderr
fi
}
read_rules() {
while read -r NAME ASSIGN RULE; do
if [ "$ASSIGN" = "<-" ]; then
RULES["$NAME"]="$RULE"
ORDER+=("$NAME")
else
echo "Error in normalization!"
exit 1
fi
done
}
read_code() {
PREFIX="$(sed '/[^ ]*\s*<-/,$d' "$1")"
SUFFIX="$(sed -n '/%%/,$p' "$1")"
}
normalize() {
sed '
/^#/d;
/^%%/,$d;
' "$1" | tr '\n' ' ' | sed '
s/\([^ ]\+\)\s*<-\s*/\n\1 <- /g;
' | sed '
s/\s*%\(header\|prefix\|auxil\|source\).*//;
/^$/d;
'
echo
}
find_simple_rules() {
for NAME in "${!RULES[@]}"; do
if [[ "${RULES[$NAME]}" =~ [/] ]]; then
continue
fi
if [[ "${RULES[$NAME]}" =~ \$[0-9] ]]; then
continue
fi
SIMPLE+=("$NAME")
done
}
inline_simple_rules() {
local PATTERNS
for RULE in "${SIMPLE[@]}"; do
PATTERN="${RULES["$RULE"]//\\/\\\\}"
PATTERN="${PATTERN//\|/\\\|}"
PATTERNS+="s|\b$RULE\b|($PATTERN)|g;"
done
for NAME in "${!RULES[@]}"; do
REPLACED="${RULES[$NAME]}"
PREV=""
while [ "$REPLACED" != "$PREV" ]; do
PREV="$REPLACED"
REPLACED="$(sed "$PATTERNS" <<<"$REPLACED")"
done
if [ "${RULES["$NAME"]}" != "$REPLACED" ]; then
dbg "Replacing simple rules in $NAME:"
dbg "- ${RULES["$NAME"]}"
dbg "+ $REPLACED"
RULES["$NAME"]="$REPLACED"
fi
done
for RULE in "${SIMPLE[@]}"; do
unset RULES["$RULE"]
done
}
print_result() {
echo "$PREFIX"
echo
for NAME in "${ORDER[@]}"; do
if [ "${RULES["$NAME"]}" ]; then
echo "$NAME <- ${RULES[$NAME]}"
fi
done
echo
echo "$SUFFIX"
}
main() {
declare -A RULES=()
declare -a SIMPLE=()
declare -a ORDER=()
if [ "$1" = "-v" ]; then
VERBOSE="true"
shift
fi
read_code "$1"
read_rules < <(normalize "$1")
find_simple_rules
dbg "Simple rules: ${SIMPLE[*]}"
inline_simple_rules
print_result
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment