|
#!/bin/bash |
|
if [ $# -lt 1 ]; then |
|
echo "usage> " $0 "program-file" |
|
exit 1 |
|
fi |
|
|
|
declare -a tl |
|
declare -a tc |
|
MAX_TC=1000 |
|
tcs=0 |
|
tcb=0 |
|
TEXT=`cat $1` #デミリタは全て1文字の空白に変換 |
|
|
|
declare -A hl_var=( [1]=dummy ) |
|
|
|
ret_getTc=0 |
|
function getTc () { |
|
local len=$2 |
|
local str="${TEXT:$1:$len}" |
|
local i |
|
for (( i=0 ; i < tcs ; i++ )) |
|
do |
|
if [[ $len = "${tl[$i]}" && $str = "${TEXT:ts[$i]:len}" ]];then |
|
break; |
|
fi |
|
done |
|
if [[ $i == $tcs ]]; then |
|
if [[ $tcs -gt $MAX_TC ]]; then |
|
echo "too many tokens" |
|
exit 1 |
|
fi |
|
ts[$i]=$1 |
|
tl[$i]="$len" |
|
let tcs++ |
|
hl_var[$i]=0 |
|
[[ $str =~ ^[0-9]*$ ]] && hl_var[$i]=$str |
|
fi |
|
ret_getTc=$i |
|
} |
|
|
|
|
|
ret_lexer=0 |
|
function lexer () { |
|
local str="$1" |
|
local len=0 |
|
local i |
|
local j=0 |
|
local sp_char="[=+-/!%&~|<>?:.#\*]" |
|
local sp_single_char="[(){}[\];,]" |
|
local AlphaNum="[A-Z|a-z|0-9]" |
|
local space=" " |
|
str_length=${#str} |
|
for (( i=0 ; ; )) |
|
do |
|
if [[ $i -ge $str_length ]] ;then |
|
ret_lexer=$j |
|
return |
|
else |
|
len=0 |
|
case "${str:$i:1}" in |
|
$space ) |
|
let i++ |
|
continue |
|
;; |
|
$sp_char ) |
|
for (( k=i ; ; )) |
|
do |
|
case "${str:$k:1}" in |
|
$sp_char ) |
|
let len++ |
|
let k++ |
|
;; |
|
* ) |
|
break |
|
;; |
|
esac |
|
done |
|
;; |
|
$sp_single_char ) |
|
let len++ |
|
;; |
|
$AlphaNum ) |
|
for (( k=i ; ; )) |
|
do |
|
case "${str:$k:1}" in |
|
$AlphaNum ) |
|
let len++ |
|
let k++ |
|
;; |
|
* ) |
|
break |
|
;; |
|
esac |
|
done |
|
;; |
|
* ) |
|
local other="${str:$i:1}" |
|
if [[ 0 = `echo -n ${other}|wc -c` ]];then |
|
let i++ |
|
continue |
|
else |
|
echo syntax error on lexer |
|
exit 1 |
|
fi |
|
;; |
|
esac |
|
fi |
|
getTc $i $len $j |
|
tc["$j"]=$ret_getTc |
|
let i+=len |
|
let j++ |
|
done |
|
} |
|
|
|
|
|
function main () { |
|
TEXT_LENGTH=${#TEXT} |
|
local PC0 |
|
local PC1 |
|
|
|
lexer "$TEXT" |
|
PC1=$ret_lexer |
|
LAST=$TEXT_LENGTH |
|
TEXT+="." |
|
|
|
getTc $LAST 1; let LAST++ |
|
tc[$PC1]=$ret_getTc |
|
tc[$((PC1+1))]=$ret_getTc |
|
tc[$((PC1+2))]=$ret_getTc |
|
tc[$((PC1+3))]=$ret_getTc |
|
TEXT+=";"; getTc $LAST 1 ; let LAST++ |
|
local TKN_semi=$ret_getTc |
|
TEXT+="="; getTc $LAST 1 ; let LAST++ |
|
local TKN_assign=$ret_getTc |
|
TEXT+="+"; getTc $LAST 1 ; let LAST++ |
|
local TKN_plus=$ret_getTc |
|
TEXT+="-"; getTc $LAST 1 ; let LAST++ |
|
local TKN_minus=$ret_getTc |
|
TEXT+=":"; getTc $LAST 1 ; let LAST++ |
|
local TKN_colon=$ret_getTc |
|
TEXT+="("; getTc $LAST 1 ; let LAST++ |
|
local TKN_Lparen=$ret_getTc |
|
TEXT+=")"; getTc $LAST 1 ; let LAST++ |
|
local TKN_Rparen=$ret_getTc |
|
TEXT+="print"; getTc $LAST 5 ; let LAST+=5 |
|
local TKN_print=$ret_getTc |
|
TEXT+="goto"; getTc $LAST 4 ; let LAST+=4 |
|
local TKN_goto=$ret_getTc |
|
TEXT+="if"; getTc $LAST 2 ; let LAST+=2 |
|
local TKN_if=$ret_getTc |
|
TEXT+="=="; getTc $LAST 2 ; let LAST+=2 |
|
local TKN_cmp_eq=$ret_getTc |
|
TEXT+="!="; getTc $LAST 2 ; let LAST+=2 |
|
local TKN_cmp_neq=$ret_getTc |
|
TEXT+="<"; getTc $LAST 1 ; let LAST++ |
|
local TKN_cmp_lt=$ret_getTc |
|
|
|
for (( PC=0 ; PC < PC1 ; PC++ )) |
|
do |
|
if [[ ${tc[$PC + 1]} == $TKN_colon ]]; then |
|
hl_var[${tc[PC]}]=$(( PC + 2)) |
|
fi |
|
done |
|
|
|
# local debug_c=0 |
|
for (( PC=0 ; PC < PC1 ; )) |
|
do |
|
# let debug_c++ |
|
# echo -n dc:$debug_c pc:$PC |
|
# for (( j=PC ; ${tc[$j]} != $TKN_semi && $j < $PC1; j++ )) |
|
# do echo -n " ${TEXT:${ts[${tc[j]}]}:${tl[${tc[j]}]}}" |
|
# done |
|
# echo ${TEXT:${ts[${tc[j]}]}:${tl[${tc[j]}]}} |
|
|
|
if [[ ${tc[$PC + 1]} == $TKN_assign && ${tc[$PC + 3]} == $TKN_semi ]]; then |
|
hl_var[${tc[PC]}]=${hl_var[${tc[PC+2]}]} |
|
elif [[ ${tc[$PC + 1]} == $TKN_assign && ${tc[$PC + 3]} == $TKN_plus && ${tc[$PC + 5]} == $TKN_semi ]] ; then |
|
hl_var[${tc[$PC]}]=$(( hl_var[${tc[$PC + 2]}] + hl_var[${tc[$PC + 4]}] )) |
|
elif [[ ${tc[$PC + 1]} == $TKN_assign && ${tc[$PC + 3]} == $TKN_minus && ${tc[$PC + 5]} == $TKN_semi ]] ; then |
|
hl_var[${tc[$PC]}]=$(( hl_var[${tc[$PC + 2]}] - hl_var[${tc[$PC + 4]}] )) |
|
elif [[ ${tc[$PC]} == $TKN_print && ${tc[$PC + 2]} == $TKN_semi ]] ; then |
|
echo ${hl_var[${tc[$PC + 1]}]} |
|
elif [[ ${tc[$PC + 1]} == $TKN_colon ]]; then |
|
let PC+=2 |
|
continue |
|
elif [[ ${tc[$PC]} == $TKN_goto && ${tc[$PC + 2]} == $TKN_semi ]]; then |
|
PC=${hl_var[${tc[PC+1]}]} |
|
continue |
|
elif [[ ${tc[$PC]} == $TKN_if && \ |
|
${tc[$PC + 1]} == $TKN_Lparen && \ |
|
${tc[$PC + 5]} == $TKN_Rparen && \ |
|
${tc[$PC + 6]} == $TKN_goto && \ |
|
${tc[$PC + 8]} == $TKN_semi ]]; then |
|
local GPC=${hl_var[${tc[PC+7]}]} |
|
local v0=${hl_var[${tc[PC+2]}]} |
|
local v1=${hl_var[${tc[PC+4]}]} |
|
if [[ ${tc[$PC + 3]} == $TKN_cmp_neq && v0 != v1 ]]; then |
|
PC=$GPC |
|
continue |
|
elif [[ ${tc[$PC + 3]} == $TKN_cmp_eq && v0 == v1 ]]; then |
|
PC=$GPC |
|
continue |
|
elif [[ ${tc[$PC + 3]} == $TKN_cmp_lt && v0 -lt v1 ]]; then |
|
PC=$GPC |
|
continue |
|
fi |
|
else |
|
echo syntax error on main |
|
exit 1 |
|
fi |
|
for ((; ${tc[$PC]} != $TKN_semi && $PC < $PC1; )) |
|
do |
|
let PC++ |
|
done |
|
let PC++ |
|
done |
|
} |
|
main |
|
set | grep ^tc= |
|
set | grep ^tcs |
|
set | grep ^ts= |
|
set | grep ^hl_var= |
|
|
|
for ((i = 0; i < ${#ts[@]}; i++)) { |
|
echo Token $i "${TEXT:${ts[$i]}:${tl[$i]}}" |
|
} |
|
|
|
exit |