#!/bin/ksh # # KornShell BASIC-to-C converter --= BACON =-- # # Peter van Eerten - March 2009. # # Global variables should be preceded with a 'g_'. # #----------------------------------------------------------- # GLOBAL INITIALIZATONS #----------------------------------------------------------- # Version of BACON g_VERSION="0.15" # Link flags g_LDFLAGS="-lm" # Amount of string functions simultanously used in one line let g_MAX_DEPTH=16 # Find 'grep' and other coretools if [[ -z `which grep` || -z `which cat` || -z `which rm` || -z `which tr` ]] then print "ERROR: 'grep', 'cat', 'rm' or 'tr' not found on this system!" exit 1 fi # Find 'indent' if [[ -z `which indent` ]] then print "WARNING: 'indent' not found on this system!" print "Generated source code will not be beautified." fi #----------------------------------------------------------- # # Parse a string into array elements, taking "" pairs into account # function Parse_String { typeset CNT IN DQ TMP PARSED= # Initialize IN="$1" CNT=0 # Get real strings first while [[ ${#IN} -gt 0 ]] do typeset -L1 DQ="$IN" if [[ ${DQ} = "\"" ]] then TMP=${IN#*\"} if [[ -z ${TMP##*;} ]] then PARSED[$CNT]="\"${TMP%%\"*}\";" IN="${TMP#*\";}" else PARSED[$CNT]="\"${TMP%%\"*}\"" IN="${TMP#*\"}" fi else PARSED[$CNT]=${IN%%,*} if [[ $IN = "${IN#*,}" ]] then IN= else IN="${IN#*,}" fi fi # Only next when there is a value if [[ ${#PARSED[$CNT]} -gt 0 ]] then ((CNT+=1)) fi done } #----------------------------------------------------------- function Handle_Print { typeset FORMAT EXP LEN DQ NR # If no argument, do nothing if [[ "$1" != "PRINT" && "$1" != "print" ]] then # If there is FORMAT/format argument if [[ "$1" = +(* FORMAT *) || "$1" = +(* format *) ]] then FORMAT=${1##* FORMAT} if [[ "$FORMAT" = "${1}" ]] then FORMAT=${1##* format} print -r "fprintf(stdout, ${FORMAT%%;*}, ${1%%format *});" >> $g_CFILE else print -r "fprintf(stdout, ${FORMAT%%;*}, ${1%%FORMAT *});" >> $g_CFILE fi else # Parse string into elements Parse_String "$1" NR=0 while [[ $NR -lt ${#PARSED[@]} ]] do # Determine element ARGS=${PARSED[$NR]} # Get expression without ; if [[ -z ${ARGS##*;} ]] then let LEN="${#ARGS}-1" typeset -L$LEN EXP="$ARGS" else EXP=${ARGS} fi typeset -R1 DQ="$EXP" # Check type of var, string? if [[ "$EXP" = +(*INSTR\(*) || "$EXP" = +(*VAL\(*) || "$EXP" = +(*instr\(*) || "$EXP" = +(*val\(*) ]] then print -r "fprintf(stdout, \"%g\", (double)($EXP));" >> $g_CFILE elif [[ "$EXP" = +(*\$*) ]] then print -r "fprintf(stdout, \"%s\", $EXP);" >> $g_CFILE # Check if it is a normal string - or'ing because of syntax highlighting elif [[ $DQ = "\"" || $DQ = "\"" ]] then print -r "fprintf(stdout, \"%s\", $EXP);" >> $g_CFILE # Other else print -r "fprintf(stdout, \"%g\", (double)($EXP));" >> $g_CFILE fi # If line ends with ';' then skip newline if [[ -n ${ARGS##*;} ]] then print -r "fprintf(stdout, \"\n\");" >> $g_CFILE fi # Next element ((NR+=1)) done fi else print -r "fprintf(stdout, \"\n\");" >> $g_CFILE fi } #----------------------------------------------------------- function Handle_Input { # Local variables typeset CHECK VAR # Check if we have an argument at all if [[ "$1" = "INPUT" ]] then print "ERROR: empty INPUT at line $g_COUNTER!" exit 1 fi # Get the variablename without surrounding spaces VAR=`print ${1}` # Translate function to C function print "fgets(__b2c__input__buffer, $g_MAX_STRING, stdin);" >> $g_CFILE # Check type of var, string? if [[ "${VAR##*$}" != "$1" ]] then CHECK=`grep -i "$VAR\[$g_MAX_STRING\];" $g_HFILE` if [[ -z $CHECK ]] then print "char $VAR[$g_MAX_STRING];" >> $g_HFILE fi # Make sure internal var is copied to var of program print "strncpy($VAR, __b2c__input__buffer, $g_MAX_STRING);" >> $g_CFILE # Get rid of the terminating newline print -r "$VAR[strlen($VAR)-1] = '\0';" >> $g_CFILE # Var is numeric else # Variable may not be array, these should be defined with DECLARE if [[ "$VAR" != +(*\[*\]*) ]] then # Not declared? Assume long CHECK=`grep -i " $VAR;" $g_HFILE` if [[ -z $CHECK ]] then print "long $VAR;" >> $g_HFILE fi else if [[ -z `grep -i " ${VAR%%\[*}\[" $g_HFILE` ]] then print "ERROR: cannot declare implicit array in INPUT statement at $g_COUNTER!" exit 1 else CHECK=`grep -i " ${VAR%%\[*}" $g_HFILE` fi fi # Make sure internal var is copied to var of program if [[ "$CHECK" = +(double *) ]] then print "$VAR = atof(__b2c__input__buffer);" >> $g_CFILE else print "$VAR = atoi(__b2c__input__buffer);" >> $g_CFILE fi fi } #----------------------------------------------------------- function Handle_For { # Local variables typeset FROM TO TMP VAR STEP CHECK # Get the variablename without surrounding spaces VAR=`print ${1%%=*}`; TMP=`print ${1#*=}` # Do we have a STRING var? if [[ "${VAR##*$}" != "$VAR" ]] then print "ERROR: variable in FOR statement at line $g_COUNTER cannot be string!" exit 1 fi # Check if TO is available if [[ "$TMP" != +(* TO *) ]] then if [[ "$TMP" != +(* to *) ]] then print "ERROR: missing TO in FOR statement at line $g_COUNTER!" exit 1 fi fi # Get the starting and ending value if [[ "$TMP" = +(* TO *) ]] then FROM=`print ${TMP%% TO *}` TO=`print ${TMP##* TO }` else FROM=`print ${TMP%% to *}` TO=`print ${TMP##* to }` fi # Check if there is a STEP if [[ "$TO" = +(* STEP *) ]] then STEP=${TO##* STEP } TO=${TO%% STEP *} elif [[ "$TO" = +(* step *) ]] then STEP=${TO##* step } TO=${TO%% step *} else STEP=1 fi # Translate function to C function if [[ $STEP -lt 0 ]] then print "for($VAR=$FROM; $VAR >= $TO; $VAR+=$STEP){" >> $g_CFILE else print "for($VAR=$FROM; $VAR <= $TO; $VAR+=$STEP){" >> $g_CFILE fi # Variable may not be array, these should be defined with DECLARE if [[ "$VAR" = +(*\[*\]*) ]] then if [[ -z `grep -i " ${VAR%%\[*}\[" $g_HFILE` ]] then print "ERROR: cannot declare implicit array in FOR statement at $g_COUNTER!" exit 1 fi else # Declare variable if not done yet, assuming integer CHECK=`grep -i " $VAR;" $g_HFILE` if [[ -z $CHECK ]] then print "long $VAR;" >> $g_HFILE fi fi } #----------------------------------------------------------- function Handle_If { # Check if THEN is available if [[ "$1" != +(* THEN) ]] then if [[ "$1" != +(* then) ]] then print "ERROR: Missing THEN in IF statement at line $g_COUNTER!" exit 1 fi fi # Translate function to C function print "if(${1% *}){" >> $g_CFILE } #----------------------------------------------------------- function Handle_Elif { # Check if THEN is available if [[ "$1" != +(* THEN) ]] then if [[ "$1" != +(* then) ]] then print "ERROR: Missing THEN in ELIF statement at line $g_COUNTER!" exit 1 fi fi # Translate function to C function print "} else if(${1% *}){" >> $g_CFILE } #----------------------------------------------------------- function Handle_While { # Check if DO is available if [[ "$1" != +(* DO) ]] then if [[ "$1" != +(* do) ]] then print "ERROR: Missing DO in WHILE statement at line $g_COUNTER!" exit 1 fi fi # Translate function to C function print "while(${1% *}){" >> $g_CFILE } #----------------------------------------------------------- function Handle_Let { # Local variables typeset VAR CHECK TMP TARGET # Check if there is an asignment at all, if not exit if [[ "$1" != +(*=*) ]] then print "ERROR: could not parse line $g_COUNTER!" exit 1 fi # Determine target if [[ -n $g_FUNCNAME ]] then TARGET=$g_CFILE else TARGET=$g_HFILE fi touch $TARGET # Get the variablename without surrounding spaces VAR=`print ${1%%=*}`; TMP=${1#*=} # Check if var is string var if [[ "${VAR}" = +(*\$) ]] then CHECK=`grep -i " $VAR\[$g_MAX_STRING\];" $TARGET` if [[ -z $CHECK ]] then print "static char $VAR[$g_MAX_STRING];" >> $TARGET fi # Variable may not be array, these should be defined with DECLARE elif [[ "$VAR" = +(*\[*\]*) ]] then print "ERROR: cannot declare array at $g_COUNTER - use DECLARE!" exit 1 # Assume Integer else CHECK=`grep -i " $VAR;" $TARGET` if [[ -z $CHECK ]] then print "long $VAR;" >> $TARGET fi fi # Do we have a STRING var? if [[ "${VAR}" = +(*\$) ]] then print "__b2c__strncpy($VAR, $TMP, $g_MAX_STRING);" >> $g_CFILE else print "$1;" >> $g_CFILE fi } #----------------------------------------------------------- function Handle_Open { # Local variables typeset FILE MODE HANDLE TMP CHECK # Check if FOR is available if [[ "$1" != +(* FOR *) ]] then if [[ "$1" != +(* for *) ]] then print "ERROR: Missing FOR in OPEN statement at line $g_COUNTER!" exit 1 fi fi # Check if AS is available if [[ "$1" != +(* AS *) ]] then if [[ "$1" != +(* as *) ]] then print "ERROR: Missing AS in OPEN statement at line $g_COUNTER!" exit 1 fi fi # Get the file, mode and handle if [[ "$1" = +(* FOR *) ]] then FILE=`print ${1%% FOR *}` TMP=`print ${1##* FOR }` else FILE=`print ${1%% for *}` TMP=`print ${1##* for }` fi if [[ "$1" = +(* AS *) ]] then MODE=`print ${TMP%% AS *}` HANDLE=`print ${TMP##* AS }` else MODE=`print ${TMP%% as *}` HANDLE=`print ${TMP##* as }` fi # Check if var is string var if [[ "${HANDLE}" = +(*\$) ]] then print "ERROR: Variable for OPEN at line $g_COUNTER cannot be string!" exit 1 fi # Check if variable was declared CHECK=`grep -i "$HANDLE;" $g_HFILE` if [[ -z $CHECK ]] then print "FILE* $HANDLE;" >> $g_HFILE fi # Convert to C syntax case $MODE in @(READING|reading) ) print "$HANDLE = fopen($FILE, \"r\");" >> $g_CFILE;; @(WRITING|writing) ) print "$HANDLE = fopen($FILE, \"w\");" >> $g_CFILE;; @(APPENDING|appending) ) print "$HANDLE = fopen($FILE, \"a\");" >> $g_CFILE;; @(READWRITE|readwrite) ) print "$HANDLE = fopen($FILE, \"r+\");" >> $g_CFILE;; esac # Error handling print "if($HANDLE == NULL){fprintf(stderr, \"ERROR: %s in OPEN statement!\\\\n\", strerror(errno)); exit(EXIT_FAILURE);}" >> $g_CFILE } #----------------------------------------------------------- function Handle_Readln { # Local variables typeset CHECK VAR FROM # Check if FROM is available if [[ "$1" != +(* FROM *) ]] then if [[ "$1" != +(* from *) ]] then print "ERROR: Missing FROM in READLN statement at line $g_COUNTER!" exit 1 fi fi # Get the variablename without surrounding spaces if [[ "$1" = +(* FROM *) ]] then VAR=`print ${1%% FROM *}` # Get filedescriptor FROM=`print ${1##* FROM }` else VAR=`print ${1%% from *}` # Get filedescriptor FROM=`print ${1##* from }` fi # Check if var is string var if [[ "${VAR}" != +(*\$) ]] then print "ERROR: Variable for READLN at line $g_COUNTER must be string!" exit 1 fi # Translate function to C function print "fgets(__b2c__input__buffer, $g_MAX_STRING, $FROM);" >> $g_CFILE # Check if variable is declared CHECK=`grep -i " $VAR\[$g_MAX_STRING\];" $g_HFILE` if [[ -z $CHECK ]] then print "char $VAR[$g_MAX_STRING];" >> $g_HFILE fi # Make sure internal var is copied to var of program print "strncpy($VAR, __b2c__input__buffer, $g_MAX_STRING);" >> $g_CFILE # Make sure to end the string print -r "$VAR[strlen(__b2c__input__buffer)] = '\0';" >> $g_CFILE } #----------------------------------------------------------- function Handle_Writeln { # Local variables typeset VAR TO # Check if TO is available if [[ "$1" != +(* TO *) ]] then if [[ "$1" != +(* to *) ]] then print "ERROR: Missing TO in WRITELN statement at line $g_COUNTER!" exit 1 fi fi # Get the variablename without surrounding spaces if [[ "$1" = +(* TO *) ]] then VAR=`print ${1%% TO *}`; # Get filedescriptor TO=`print ${1##* TO }` else VAR=`print ${1%% to *}`; # Get filedescriptor TO=`print ${1##* to }` fi # Check if var is string var if [[ "${VAR}" != +(*\$) && "$VAR" = `print "$VAR" | tr -d "\042"` ]] then print "ERROR: Variable for WRITELN at line $g_COUNTER must be string!" exit 1 fi # Translate function to C function print "fprintf($TO, \"%s\\\\n\", $VAR);" >> $g_CFILE } #----------------------------------------------------------- function Handle_Import { # Local variables typeset TMP SYM LIB CHECK TOKEN PTR typeset -l TYPE # Check if FROM is available if [[ "$1" != +(* FROM *) ]] then if [[ "$1" != +(* from *) ]] then print "ERROR: missing FROM in IMPORT statement at line $g_COUNTER!" exit 1 fi fi # Get the symbolname without surrounding spaces and doublequotes if [[ "$1" = +(* FROM *) ]] then SYM=`print ${1%% FROM *}`; TMP=${1#* FROM } TOKEN=`print $SYM | tr -d "\042"` else SYM=`print ${1%% from *}`; TMP=${1#* from } TOKEN=`print $SYM | tr -d "\042"` fi # Check if TYPE is available if [[ "$1" != +(* TYPE *) ]] then if [[ "$1" != +(* type *) ]] then print "ERROR: missing TYPE in IMPORT statement at line $g_COUNTER!" exit 1 fi fi # Get library and type if [[ "$1" = +(* TYPE *) ]] then LIB=`print ${TMP%% TYPE *}` TYPE=`print ${TMP##* TYPE }` else LIB=`print ${TMP%% type *}` TYPE=`print ${TMP##* type }` fi # If library is libm or libc, skip dlopen as we're linking with those anyway if [[ $LIB != +(*libc.so*) && $LIB != +(*libm.so*) ]] then # Create name from libname PTR=`print $LIB | tr -d [:punct:]` # Check if variable was declared CHECK=`grep -i "void\* __b2c__dlopen__pointer_$PTR;" $g_HFILE` if [[ -z $CHECK ]] then print "void* __b2c__dlopen__pointer_$PTR;" >> $g_HFILE print "__b2c__dlopen__pointer_$PTR = dlopen($LIB, RTLD_GLOBAL|RTLD_LAZY);" >> $g_CFILE print "if(__b2c__dlopen__pointer_$PTR == NULL) {" >> $g_CFILE print "fprintf(stderr, \"ERROR: %s\\\\n\", dlerror()); exit(EXIT_FAILURE);}" >> $g_CFILE fi # Check if token was declared CHECK=`grep -i "$TYPE (\*$TOKEN)();" $g_HFILE` if [[ -z $CHECK ]] then print "$TYPE (*$TOKEN)();" >> $g_HFILE fi # Translate to C function print "*($TYPE **) (&$TOKEN) = dlsym(__b2c__dlopen__pointer_$PTR, $SYM);" >> $g_CFILE print "if($TOKEN == NULL) {fprintf(stderr, \"ERROR: could not find symbol '$TOKEN' in library!\\\\n\"); exit(EXIT_FAILURE);}" >> $g_CFILE # Add link flag if [[ $g_LDFLAGS != +(*-ldl*) ]] then g_LDFLAGS="$g_LDFLAGS -ldl" fi fi # Make symbol known to parser g_IMPORTED="$TOKEN $g_IMPORTED" } #----------------------------------------------------------- function Handle_Declare { # Local variables typeset VAR TYPE CHECK # Check if TYPE is available if [[ "$1" != +(* TYPE *) ]] then if [[ "$1" != +(* type *) ]] then print "ERROR: Missing TYPE in DECLARE statement at line $g_COUNTER!" exit 1 fi fi # Get the variablename and type if [[ "$1" = +(* TYPE *) ]] then VAR=`print ${1%% TYPE *}` TYPE=`print ${1##* TYPE }` else VAR=`print ${1%% type *}` TYPE=`print ${1##* type }` fi # Check if variable was already declared CHECK=`grep -i " $VAR;" $g_HFILE` if [[ -n $CHECK ]] then print "ERROR: variable in DECLARE statement at line $g_COUNTER was defined previously!" exit 1 fi # Translate function to C function if [[ -n $g_FUNCNAME ]] then print "$TYPE $VAR;" >> $g_CFILE else print "$TYPE $VAR;" >> $g_HFILE fi } #----------------------------------------------------------- function Handle_Read { # Local variables typeset CHECK # Check if we have an argument at all if [[ "$1" = "READ" ]] then print "ERROR: empty READ at line $g_COUNTER!" exit 1 fi # Check type of var, string? if [[ "${1##*$}" != "$1" ]] then CHECK=`grep -i "$1\[$g_MAX_STRING\];" $g_HFILE` if [[ -z $CHECK ]] then print "char $1[$g_MAX_STRING];" >> $g_HFILE fi # Convert to C print "strncpy(${1#* }, __b2c__stringarray[__b2c__stringarray_ptr], $g_MAX_STRING);" >> $g_CFILE print "__b2c__stringarray_ptr++;" >> $g_CFILE else # Variable may not be array, these should be defined with DECLARE if [[ "$1" != +(*\[*\]*) ]] then # Not declared? Assume long CHECK=`grep -i " $1;" $g_HFILE` if [[ -z $CHECK ]] then print "long $1;" >> $g_HFILE fi else if [[ -z `grep -i " ${1%%\[*}\[" $g_HFILE` ]] then print "ERROR: cannot declare implicit array in READ statement at $g_COUNTER!" exit 1 else # See how var was declared CHECK=`grep -i " ${1%%\[*}" $g_HFILE` fi fi # Convert to C if [[ "$CHECK" = +(double *) ]] then print "${1#* } = __b2c__floatarray[__b2c__floatarray_ptr];" >> $g_CFILE print "__b2c__floatarray_ptr++;" >> $g_CFILE else print "${1#* } = __b2c__intarray[__b2c__intarray_ptr];" >> $g_CFILE print "__b2c__intarray_ptr++;" >> $g_CFILE fi fi } #----------------------------------------------------------- function Handle_Function { # Check if we have an argument at all if [[ "$1" = "FUNCTION" ]] then print "ERROR: empty FUNCTION at line $g_COUNTER!" exit 1 fi # Check if we are in a function already if [[ -n $g_FUNCNAME ]] then print "ERROR: cannot define FUNCTION within FUNCTION at line $g_COUNTER!" exit 1 fi # Get the funcname g_ORIGFUNCNAME=`print ${1}` if [[ "$g_ORIGFUNCNAME" = +(*\(*\)*) ]] then g_FUNCNAME=`print ${g_ORIGFUNCNAME%%\(*}` else g_FUNCNAME=`print ${g_ORIGFUNCNAME}` fi # Switch to header file g_COPY_CFILE=$g_CFILE g_CFILE=$g_CFILE.$g_FUNCNAME.tmp } #----------------------------------------------------------- function Handle_Endfunction { # Check if return was found if [[ -z $g_FUNCTYPE ]] then print "ERROR: function '$g_FUNCNAME' was defined without returning a value or string!" exit 1 fi # Now setup function in main program if [[ $g_ORIGFUNCNAME != +(*\(*\)*) ]] then print "$g_FUNCTYPE __b2c__function__$g_ORIGFUNCNAME(void) {" > ${g_COPY_CFILE%.*}.$g_FUNCNAME.h else print "$g_FUNCTYPE __b2c__function__$g_ORIGFUNCNAME {" > ${g_COPY_CFILE%.*}.$g_FUNCNAME.h fi # Add function body cat $g_CFILE >> ${g_COPY_CFILE%.*}.$g_FUNCNAME.h print "}" >> ${g_COPY_CFILE%.*}.$g_FUNCNAME.h # Include header file print "#include \"${g_COPY_CFILE%\.*}.$g_FUNCNAME.h\"" >> $g_HFILE # Delete temp funcfile rm $g_CFILE # Restore mainfile g_CFILE=$g_COPY_CFILE # Create macro if [[ $g_ORIGFUNCNAME != +(*\(*\)*) ]] then print "#define $g_FUNCNAME __b2c__function__$g_FUNCNAME()" >> $g_HFILE else print "#define $g_FUNCNAME(...) __b2c__function__$g_FUNCNAME(__VA_ARGS__)" >> $g_HFILE fi # Clear function variables g_ORIGFUNCNAME= g_FUNCNAME= g_FUNCTYPE= } #----------------------------------------------------------- function Handle_Return { # Local variables typeset CHECK # Check if we have an argument at all if [[ "$1" = "RETURN" ]] then print "ERROR: empty RETURN at line $g_COUNTER!" exit 1 fi CHECK=`grep -i " $1;" $g_CFILE` # Check type of var, string? if [[ "${1}" = +(*\$*) ]] then g_FUNCTYPE="char * " # Check if it is a normal string elif [[ "$1" != `print "$1" | tr -d "\042"` ]] then g_FUNCTYPE="char * " # Check if float elif [[ "$1" = +(*.*) ]] then g_FUNCTYPE="double " # Check if no alpha chars (then integer value) elif [[ "$1" = +(![a-zA-Z]) ]] then g_FUNCTYPE="long " # Assume variable, check if declared before elif [[ -n $CHECK ]] then if [[ $CHECK = +(double*) ]] then g_FUNCTYPE="double " else g_FUNCTYPE="long " fi # Not declared, assume integer variable else g_FUNCTYPE="long " fi print "return (${1});" >> $g_CFILE } #----------------------------------------------------------- function Handle_Push { # Local variables typeset CHECK # Check if we have an argument at all if [[ "$1" = "PUSH" ]] then print "ERROR: empty PUSH at line $g_COUNTER!" exit 1 fi CHECK=`grep -i " $1;" $g_HFILE` # Check type of var, string? if [[ "${1}" = +(*\$*) ]] then print "strncpy(__b2c__stringstack[__b2c__stackptr], $1, $g_MAX_STRING);" >> $g_CFILE print "__b2c__typestack[__b2c__stackptr] = 1;" >> $g_CFILE # Check if it is a normal string elif [[ "$1" != `print "$1" | tr -d "\042"` ]] then print "strncpy(__b2c__stringstack[__b2c__stackptr], $1, $g_MAX_STRING);" >> $g_CFILE print "__b2c__typestack[__b2c__stackptr] = 1;" >> $g_CFILE # Check if float elif [[ "$1" = +(*.*) ]] then print "__b2c__doublestack[__b2c__stackptr] = $1;" >> $g_CFILE print "__b2c__typestack[__b2c__stackptr] = 2;" >> $g_CFILE # Check if no alpha chars (then integer value) elif [[ "$1" = +(![a-zA-Z]) ]] then print "__b2c__longstack[__b2c__stackptr] = $1;" >> $g_CFILE print "__b2c__typestack[__b2c__stackptr] = 3;" >> $g_CFILE # Assume variable, check if declared before elif [[ -n $CHECK ]] then if [[ $CHECK = +(double*) ]] then print "__b2c__doublestack[__b2c__stackptr] = $1;" >> $g_CFILE print "__b2c__typestack[__b2c__stackptr] = 2;" >> $g_CFILE else print "__b2c__longstack[__b2c__stackptr] = $1;" >> $g_CFILE print "__b2c__typestack[__b2c__stackptr] = 3;" >> $g_CFILE fi # Not declared, assume integer variable else print "__b2c__longstack[__b2c__stackptr] = $1;" >> $g_CFILE print "__b2c__typestack[__b2c__stackptr] = 3;" >> $g_CFILE fi # Increase stackpointer print "__b2c__stackptr++;" >> $g_CFILE print "if(__b2c__stackptr == $g_STACK_DEPTH) __b2c__stackptr=$g_STACK_DEPTH-1;" >> $g_CFILE } #----------------------------------------------------------- function Handle_Pull { typeset CHECK # Check if we have an argument at all if [[ "$1" = "PULL" ]] then print "ERROR: empty PULL at line $g_COUNTER!" exit 1 fi # Argument must be a variable if [[ "$1" = +(![a-zA-Z]) ]] then print "ERROR: argument in PULL statement at line $g_COUNTER is not a variable!" exit 1 fi # Decrease stackpointer again print "__b2c__stackptr--;" >> $g_CFILE print "if(__b2c__stackptr < 0) __b2c__stackptr=0;" >> $g_CFILE # Get the last value from stack if [[ "${1##*$}" != "$1" ]] then CHECK=`grep -i "$1\[$g_MAX_STRING\];" $g_HFILE` if [[ -z $CHECK ]] then print "char $1[$g_MAX_STRING];" >> $g_HFILE fi print "if(__b2c__typestack[__b2c__stackptr] == 1) strncpy($1, __b2c__stringstack[__b2c__stackptr], $g_MAX_STRING);" >> $g_CFILE else # Variable may not be array, these should be defined with DECLARE if [[ "$1" != +(*\[*\]*) ]] then # Not declared? Assume long CHECK=`grep -i " $1;" $g_HFILE` if [[ -z $CHECK ]] then print "long $1;" >> $g_HFILE fi else if [[ -z `grep -i " ${1%%\[*}\[" $g_HFILE` ]] then print "ERROR: cannot declare implicit array in INPUT statement at $g_COUNTER!" exit 1 else # See how var was declared CHECK=`grep -i " ${1%%\[*}" $g_HFILE` fi fi # Make sure internal var is copied to var of program if [[ "$CHECK" = +(double *) ]] then print "if(__b2c__typestack[__b2c__stackptr] == 2) $1=__b2c__doublestack[__b2c__stackptr];" >> $g_CFILE else print "if(__b2c__typestack[__b2c__stackptr] == 3) $1=__b2c__longstack[__b2c__stackptr];" >> $g_CFILE fi fi } #----------------------------------------------------------- # # Simple parser to tokenize line. # # Each line should begin with a statement. # The rest of the line may contain functions, these are # converted using C macros. # #----------------------------------------------------------- function Parse_Line { typeset FOUND SYM INC COPY_COUNTER typeset -u STATEMENT # Get statement without spaces STATEMENT=`print "${1%% *}"` case "$STATEMENT" in "PRINT") Handle_Print "${1#* }";; "INPUT") Handle_Input "${1#* }";; "FOR") Handle_For "${1#* }";; "NEXT") print "}" >> $g_CFILE;; "IF") Handle_If "${1#* }";; "ELIF") Handle_Elif "${1#* }";; "ELSE") print "} else {" >> $g_CFILE;; "ENDIF") print "}" >> $g_CFILE;; "WHILE") Handle_While "${1#* }";; "WEND") print "}" >> $g_CFILE;; "BREAK") print "break;" >> $g_CFILE;; "REPEAT") print "do{" >> $g_CFILE;; "UNTIL") # Check argument if [[ "${1%% *}" = "${1#* }" ]] then print "ERROR: empty AS at line $g_COUNTER!" exit 1 else print "} while(!(${1#* }));" >> $g_CFILE fi;; "LET") Handle_Let "${1#* }";; +(REM*) ) ;; "SYSTEM") # Check argument if [[ "${1%% *}" = "${1#* }" ]] then print "ERROR: empty SYSTEM at line $g_COUNTER!" exit 1 else print "SYSTEM (${1#* });" >> $g_CFILE fi;; "SLEEP") # Check argument if [[ "${1%% *}" = "${1#* }" ]] then print "ERROR: empty SLEEP at line $g_COUNTER!" exit 1 else print "usleep(${1#* }*1000);" >> $g_CFILE fi;; "OPEN") Handle_Open "${1#* }";; "CLOSE") # Check argument if [[ "${1%% *}" = "${1#* }" ]] then print "ERROR: empty CLOSE at line $g_COUNTER!" exit 1 else print "fclose(${1#* });" >> $g_CFILE fi;; "REWIND") # Check argument if [[ "${1%% *}" = "${1#* }" ]] then print "ERROR: empty REWIND at line $g_COUNTER!" exit 1 else print "rewind(${1#* });" >> $g_CFILE fi;; "READLN") Handle_Readln "${1#* }";; "WRITELN") Handle_Writeln "${1#* }";; "END") print "exit(EXIT_SUCCESS);" >> $g_CFILE;; "SUB") # Check argument if [[ "${1%% *}" = "${1#* }" ]] then print "ERROR: empty SUB at line $g_COUNTER!" exit 1 else g_ORIGFUNCNAME="${1#* }" if [[ "$g_ORIGFUNCNAME" = +(*\(*\)*) ]] then g_FUNCNAME="${g_ORIGFUNCNAME%%\(*}" else g_FUNCNAME="$g_ORIGFUNCNAME" fi g_COPY_CFILE=$g_CFILE g_CFILE=${g_CFILE%.*}.$g_FUNCNAME.h if [[ "$g_ORIGFUNCNAME" = +(*\(*\)*) ]] then print "void ${g_ORIGFUNCNAME} {" > $g_CFILE else print "void ${g_FUNCNAME}(void) {" > $g_CFILE fi # Make symbol known to parser g_IMPORTED="$g_FUNCNAME $g_IMPORTED" fi;; "ENDSUB") print "}" >> $g_CFILE # Include header file print "#include \"${g_CFILE}\"" >> $g_HFILE g_FUNCNAME= g_ORIGFUNCNAME= g_CFILE=$g_COPY_CFILE;; "CALL") # Check argument if [[ "${1%% *}" = "${1#* }" ]] then print "ERROR: empty CALL at line $g_COUNTER!" exit 1 else if [[ "${1#* }" = +(*\(*\)*) ]] then print "${1#* };" >> $g_CFILE else print "${1#* }();" >> $g_CFILE fi fi;; "FUNCTION") Handle_Function "${1#* }";; "ENDFUNCTION") Handle_Endfunction;; "RETURN") Handle_Return "${1#* }";; "IMPORT") Handle_Import "${1#* }";; "DECLARE") Handle_Declare "${1#* }";; "DATA") # Check argument if [[ "${1%% *}" = "${1#* }" ]] then print "ERROR: empty DATA at line $g_COUNTER!" exit 1 else if [[ "${1#* }" != `print "${1#* }" | tr -d "\042"` ]] then print -r "${1#* }, " >> $STRINGARRAYFILE else # Check if float if [[ "${1#* }" = +(*.*) ]] then print -r "${1#* }, " >> $FLOATARRAYFILE else print -r "${1#* }, " >> $INTARRAYFILE fi fi fi;; "RESTORE") print "if(__b2c__intarray_ptr > 0) __b2c__intarray_ptr = 0;" >> $g_CFILE print "if(__b2c__floatarray_ptr > 0) __b2c__floatarray_ptr = 0;" >> $g_CFILE print "if(__b2c__stringarray_ptr > 0) __b2c__stringarray_ptr = 0;" >> $g_CFILE;; "READ") Handle_Read "${1#* }";; "PUSH") Handle_Push "${1#* }";; "PULL") Handle_Pull "${1#* }";; "INCLUDE") # Get rid of doublequotes if they are there INC=`print ${1#* } | tr -d "\042"` # Check argument if [[ ! -f $INC || "${1%% *}" = "${1#* }" ]] then print "ERROR: missing file for INCLUDE at line $g_COUNTER!" exit 1 else # Start walking through program COPY_COUNTER=$g_COUNTER g_COUNTER=1 while read -r LINE do # Line is not empty? if [[ -n "$LINE" ]] then Parse_Line "$LINE" fi ((g_COUNTER+=1)) done < $INC # Restore original counter g_COUNTER=$COPY_COUNTER fi;; "POKE") # Check argument if [[ "${1%% *}" = "${1#* }" ]] then print "ERROR: empty POKE at line $g_COUNTER!" exit 1 else # Resolve this with C macro because of casting to (char) print "POKE(${1#* });" >> $g_CFILE fi;; *) # Check on imported symbols first FOUND=0 for SYM in $g_IMPORTED do if [[ "$1" = +($SYM*) ]] then FOUND=1 if [[ "$1" != ${1#*\(} ]] then print -r "($SYM)(${1#*\(};" >> $g_CFILE else print -r "($SYM)();" >> $g_CFILE fi fi done # Not an imported symbol? Check if assignment if [[ $FOUND -eq 0 ]] then Handle_Let "$1" fi;; esac } #----------------------------------------------------------- # # Main program # #----------------------------------------------------------- # Default BACON settings let g_MAX_STRING=256 let g_NO_COMPILE=0 let g_STACK_DEPTH=8 g_CCNAME=gcc CCFLAGS= # Some global declarations g_FUNCNAME= g_FUNCTYPE= # Get arguments while getopts ":m:c:s:gnv" OPT do case $OPT in m) g_MAX_STRING=$OPTARG;; c) g_CCNAME=$OPTARG;; s) g_STACK_DEPTH=$OPTARG;; n) g_NO_COMPILE=1;; g) CCFLAGS="-g";; v) print print "BACON version $g_VERSION - (c) Peter van Eerten - GPL." print exit 0;; \?) print print "USAGE: bacon [options] program[.bac]" print print "OPTIONS:" print print " -m \tMax string length (default: 256)" print " -c \tCompiler to use (default: gcc)" print " -s \tDepth of stack (default: 8)" print " -n \t\tDo not compile automatically" print " -g \t\tCompile with debug info" print " -v \t\tShow version" print exit 1;; esac done shift $(($OPTIND-1)) # Check if a filename was entered, if so get it if [[ $# -eq 0 ]] then print "ERROR: no filename? Run with '-?' to see usage." exit 1 elif [[ "$@" != +(*.bac) ]] then SOURCEFILE="$@.bac" else SOURCEFILE="$@" fi # Check if file exists if [[ ! -f $SOURCEFILE ]] then print "ERROR: file not found!" exit 1 fi print -n "Starting conversion... " # Now create the global filenames where to write to g_CFILE=${SOURCEFILE%.*}.c g_HFILE=${SOURCEFILE%.*}.h STRINGARRAYFILE=${SOURCEFILE%.*}.string INTARRAYFILE=${SOURCEFILE%.*}.int FLOATARRAYFILE=${SOURCEFILE%.*}.float # Create basic C file print "/* Created with BACON - PvE 2009 */" > $g_CFILE print "#include \"$g_HFILE\"" >> $g_CFILE print "int main(int argc, const char **argv)" >> $g_CFILE print "{" >> $g_CFILE # Put arguments into reserved variable ARGUMENT print "/* Setup the reserved variable 'ARGUMENT' */" >> $g_CFILE print "for(__b2c__counter=1; __b2c__counter < argc; __b2c__counter++)" >> $g_CFILE print "{strncat(ARGUMENT\$, argv[__b2c__counter], $g_MAX_STRING); if(__b2c__counter != argc - 1) strcat(ARGUMENT\$, \" \");" >> $g_CFILE print "strncat(argument\$, argv[__b2c__counter], $g_MAX_STRING); if(__b2c__counter != argc - 1) strcat(argument\$, \" \");}" >> $g_CFILE print "/* Rest of the program */" >> $g_CFILE # Create basic H file, functions are converted using macros print "/* Created with BACON - PvE 2009 */" > $g_HFILE print >> $g_HFILE print "#include " >> $g_HFILE print >> $g_HFILE print "/* Math functions */" >> $g_HFILE print "#include " >> $g_HFILE print "#define sqr(x) sqrt(x)" >> $g_HFILE print "#define SQR(x) sqrt(x)" >> $g_HFILE print "#define POW(x, y) pow(x, y)" >> $g_HFILE print "#define SIN(x) sin(x)" >> $g_HFILE print "#define COS(x) cos(x)" >> $g_HFILE print "#define TAN(x) tan(x)" >> $g_HFILE print "#define round(x) lrint(x)" >> $g_HFILE print "#define ROUND(x) lrint(x)" >> $g_HFILE print "#define mod(x,y) (x%y)" >> $g_HFILE print "#define MOD(x,y) (x%y)" >> $g_HFILE print "#define FLOOR(x) floor(x)" >> $g_HFILE print >> $g_HFILE print "/* Other functions */" >> $g_HFILE print "#include " >> $g_HFILE print "#define val(x) ((x != NULL) ? atol(x) : 0)" >> $g_HFILE print "#define VAL(x) ((x != NULL) ? atol(x) : 0)" >> $g_HFILE print >> $g_HFILE print "/* Unix functions */" >> $g_HFILE print "#include " >> $g_HFILE print "#define SYSTEM(x) ((x != NULL) ? system(x) : 0)" >> $g_HFILE print >> $g_HFILE print "/* String functions */" >> $g_HFILE print "#include " >> $g_HFILE print "char __b2c__input__buffer[$g_MAX_STRING];" >> $g_HFILE print "char __b2c__stringbuffer[$g_MAX_STRING*$g_MAX_DEPTH];" >> $g_HFILE print "int __b2c__stringbuffer_ptr = 0;" >> $g_HFILE print "char* __b2c__strncpy(char *dest, const char *src, size_t n){" >> $g_HFILE print "size_t __b2c__i; for (__b2c__i = 0; __b2c__i < n && src[__b2c__i] != '\\\\0'; __b2c__i++) dest[__b2c__i] = src[__b2c__i];" >> $g_HFILE print "dest[__b2c__i] = '\\\\0'; __b2c__stringbuffer_ptr+=$g_MAX_STRING;" >> $g_HFILE print "if(__b2c__stringbuffer_ptr >= $g_MAX_STRING*$g_MAX_DEPTH) __b2c__stringbuffer_ptr = 0; return dest;}" >> $g_HFILE print "char* __b2c__reverse(char *s){int __b2c__i; char *__b2c__tmp; __b2c__tmp = __b2c__stringbuffer + __b2c__stringbuffer_ptr;" >> $g_HFILE print "for(__b2c__i=0;__b2c__i> $g_HFILE print "if(__b2c__stringbuffer_ptr >= $g_MAX_STRING*$g_MAX_DEPTH) __b2c__stringbuffer_ptr = 0;" >> $g_HFILE print "return(__b2c__tmp);}" >> $g_HFILE print "#define reverse\$(x) ((x != NULL) ? __b2c__reverse(x) : \"null\")" >> $g_HFILE print "#define REVERSE\$(x) ((x != NULL) ? __b2c__reverse(x) : \"null\")" >> $g_HFILE print "char* __b2c__str(double d){char *__b2c__tmp; __b2c__tmp = __b2c__stringbuffer + __b2c__stringbuffer_ptr;" >> $g_HFILE print "snprintf(__b2c__tmp, $g_MAX_STRING, \"%g\", d); __b2c__stringbuffer_ptr+=$g_MAX_STRING;" >> $g_HFILE print "if(__b2c__stringbuffer_ptr >= $g_MAX_STRING*$g_MAX_DEPTH) __b2c__stringbuffer_ptr = 0;" >> $g_HFILE print "return(__b2c__tmp);}" >> $g_HFILE print "#define str\$(x) __b2c__str(x)" >> $g_HFILE print "#define STR\$(x) __b2c__str(x)" >> $g_HFILE print "#include " >> $g_HFILE print "char* __b2c__concat(char *__b2c__first, ...){ char *__b2c__tmp; char *__b2c__retbuffer; va_list __b2c__ap;" >> $g_HFILE print " __b2c__retbuffer = __b2c__stringbuffer + __b2c__stringbuffer_ptr; if(__b2c__first == NULL) return (\"null\");" >> $g_HFILE print "(void)strncpy(__b2c__retbuffer, __b2c__first, $g_MAX_STRING); va_start(__b2c__ap, __b2c__first);" >> $g_HFILE print "while((__b2c__tmp = va_arg(__b2c__ap, char *)) != NULL) (void)strncat(__b2c__retbuffer, __b2c__tmp, $g_MAX_STRING);" >> $g_HFILE print "va_end(__b2c__ap); __b2c__stringbuffer_ptr+=$g_MAX_STRING;" >> $g_HFILE print "if(__b2c__stringbuffer_ptr >= $g_MAX_STRING*$g_MAX_DEPTH) __b2c__stringbuffer_ptr = 0; return(__b2c__retbuffer);}" >> $g_HFILE print "#define concat\$(...) __b2c__concat(__VA_ARGS__, (char*)NULL)" >> $g_HFILE print "#define CONCAT\$(...) __b2c__concat(__VA_ARGS__, (char*)NULL)" >> $g_HFILE print "#define left\$(x, y) ((x != NULL && y < strlen(x) && y >= 0) ? __b2c__strncpy(__b2c__stringbuffer + __b2c__stringbuffer_ptr, x, (y)) : x)" >> $g_HFILE print "#define LEFT\$(x, y) ((x != NULL && y < strlen(x) && y >= 0) ? __b2c__strncpy(__b2c__stringbuffer + __b2c__stringbuffer_ptr, x, (y)) : x)" >> $g_HFILE print "#define right\$(x, y) ((x != NULL && y < strlen(x) && y >= 0) ? __b2c__strncpy(__b2c__stringbuffer + __b2c__stringbuffer_ptr, x+strlen(x)-(int)(y), (y)) : \"\")" >> $g_HFILE print "#define RIGHT\$(x, y) ((x != NULL && y < strlen(x) && y >= 0) ? __b2c__strncpy(__b2c__stringbuffer + __b2c__stringbuffer_ptr, x+strlen(x)-(int)(y), (y)) : \"\")" >> $g_HFILE print "#define mid\$(x, y, z) ((x != NULL && y <= strlen(x) && y > 0) ? __b2c__strncpy(__b2c__stringbuffer + __b2c__stringbuffer_ptr, x+(int)(y)-1, (z)) : \"\")" >> $g_HFILE print "#define MID\$(x, y, z) ((x != NULL && y <= strlen(x) && y > 0) ? __b2c__strncpy(__b2c__stringbuffer + __b2c__stringbuffer_ptr, x+(int)(y)-1, (z)) : \"\")" >> $g_HFILE print "long __b2c__instr (char *__b2c__x, char *__b2c__y, int z){char* __b2c__tmp;" >> $g_HFILE print "__b2c__tmp = strstr(__b2c__x+z-1, __b2c__y); if(__b2c__tmp == NULL) return (0); return (__b2c__tmp - __b2c__x + 1);}" >> $g_HFILE print "#define instr(x, y, z) ((x != NULL && y != NULL && strstr(x, y) != NULL && z > 0 && z <= strlen(x)) ? __b2c__instr(x, y, z) : 0)" >> $g_HFILE print "#define INSTR(x, y, z) ((x != NULL && y != NULL && strstr(x, y) != NULL && z > 0 && z <= strlen(x)) ? __b2c__instr(x, y, z) : 0)" >> $g_HFILE print "#define len(x) ((x != NULL) ? strlen(x) : 0)" >> $g_HFILE print "#define LEN(x) ((x != NULL) ? strlen(x) : 0)" >> $g_HFILE print "#define equal(x, y) ((x != NULL && y != NULL) ? !strncmp(x, y, $g_MAX_STRING) : 0)" >> $g_HFILE print "#define EQUAL(x, y) ((x != NULL && y != NULL) ? !strncmp(x, y, $g_MAX_STRING) : 0)" >> $g_HFILE print "#define getenviron\$(x) ((x != NULL) ? getenv(x) : \"null\")" >> $g_HFILE print "#define GETENVIRON\$(x) ((x != NULL) ? getenv(x) : \"null\")" >> $g_HFILE print >> $g_HFILE print "/* CHAR functions */" >> $g_HFILE print "#include " >> $g_HFILE print "char* __b2c__ucase(char *s){int __b2c__i; char *__b2c__tmp; __b2c__tmp = __b2c__stringbuffer + __b2c__stringbuffer_ptr;" >> $g_HFILE print "for(__b2c__i=0; __b2c__i < strlen(s); __b2c__i++){__b2c__tmp[__b2c__i]=toupper(s[__b2c__i]);} __b2c__stringbuffer_ptr+=$g_MAX_STRING;" >> $g_HFILE print "if(__b2c__stringbuffer_ptr >= $g_MAX_STRING*$g_MAX_DEPTH) __b2c__stringbuffer_ptr = 0;" >> $g_HFILE print "return(__b2c__tmp);}" >> $g_HFILE print "#define ucase\$(x) ((x != NULL) ? __b2c__ucase(x) : \"null\")" >> $g_HFILE print "#define UCASE\$(x) ((x != NULL) ? __b2c__ucase(x) : \"null\")" >> $g_HFILE print "char* __b2c__lcase(char *s){int __b2c__i; char *__b2c__tmp; __b2c__tmp = __b2c__stringbuffer + __b2c__stringbuffer_ptr;" >> $g_HFILE print "for(__b2c__i=0; __b2c__i < strlen(s); __b2c__i++){__b2c__tmp[__b2c__i]=tolower(s[__b2c__i]);} __b2c__stringbuffer_ptr+=$g_MAX_STRING;" >> $g_HFILE print "if(__b2c__stringbuffer_ptr >= $g_MAX_STRING*$g_MAX_DEPTH) __b2c__stringbuffer_ptr = 0;" >> $g_HFILE print "return(__b2c__tmp);}" >> $g_HFILE print "#define lcase\$(x) ((x != NULL) ? __b2c__lcase(x) : \"null\")" >> $g_HFILE print "#define LCASE\$(x) ((x != NULL) ? __b2c__lcase(x) : \"null\")" >> $g_HFILE print >> $g_HFILE print "/* I/O functions */" >> $g_HFILE print "char* __b2c__dec2hex(int i){char *tmp; tmp=__b2c__stringbuffer + __b2c__stringbuffer_ptr;" >> $g_HFILE print "snprintf(tmp, $g_MAX_STRING, \"%X\", i); __b2c__stringbuffer_ptr+=$g_MAX_STRING;" >> $g_HFILE print "if(__b2c__stringbuffer_ptr >= $g_MAX_STRING*$g_MAX_DEPTH) __b2c__stringbuffer_ptr = 0;" >> $g_HFILE print "return(tmp);}" >> $g_HFILE print "long __b2c__hex2dec(char *h){int __b2c__i; if(sscanf(h, \"%X\", &__b2c__i) == EOF){" >> $g_HFILE print "fprintf(stderr, \"ERROR: wrong value in DEC!\\\\n\"); exit(EXIT_FAILURE);}; return(long)(__b2c__i);}" >> $g_HFILE print "unsigned char __b2c__char2asc(char *c){return (unsigned char)*c;}" >> $g_HFILE print "char* __b2c__asc2char(int i){char *tmp; tmp=__b2c__stringbuffer + __b2c__stringbuffer_ptr;" >> $g_HFILE print "sprintf(tmp, \"%c\", i); __b2c__stringbuffer_ptr+=$g_MAX_STRING;" >> $g_HFILE print "if(__b2c__stringbuffer_ptr >= $g_MAX_STRING*$g_MAX_DEPTH) __b2c__stringbuffer_ptr = 0;" >> $g_HFILE print "return(tmp);}" >> $g_HFILE print "#define ENDFILE(x) feof(x)" >> $g_HFILE print "#define hex\$(x) __b2c__dec2hex(x)" >> $g_HFILE print "#define HEX\$(x) __b2c__dec2hex(x)" >> $g_HFILE print "#define dec(x) __b2c__hex2dec(x)" >> $g_HFILE print "#define DEC(x) __b2c__hex2dec(x)" >> $g_HFILE print "#define asc(x) __b2c__char2asc(x)" >> $g_HFILE print "#define ASC(x) __b2c__char2asc(x)" >> $g_HFILE print "#define chr\$(x) ((x < 256 && x >= 0) ? __b2c__asc2char(x) : \"\")" >> $g_HFILE print "#define CHR\$(x) ((x < 256 && x >= 0) ? __b2c__asc2char(x) : \"\")" >> $g_HFILE print >> $g_HFILE print "/* Dynamic loading, errors */" >> $g_HFILE print "#include " >> $g_HFILE print "#include " >> $g_HFILE print >> $g_HFILE print "/* GETKEY */" >> $g_HFILE print "#include " >> $g_HFILE print "long __b2c__getch(){long ch; struct termios oldt, newt; tcgetattr(0, &oldt);" >> $g_HFILE print "newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(0, TCSANOW, &newt);" >> $g_HFILE print "ch = getchar(); tcsetattr(0, TCSANOW, &oldt); return ch;} " >> $g_HFILE print "#define GETKEY __b2c__getch()" >> $g_HFILE print >> $g_HFILE print "/* Constants, logical stuff */" >> $g_HFILE print "#define pi 3.14159265" >> $g_HFILE print "#define PI 3.14159265" >> $g_HFILE print "#define not(x) (!(x))" >> $g_HFILE print "#define NOT(x) (!(x))" >> $g_HFILE print "#define and &&" >> $g_HFILE print "#define AND &&" >> $g_HFILE print "#define or ||" >> $g_HFILE print "#define OR ||" >> $g_HFILE print "#define eq ==" >> $g_HFILE print "#define EQ ==" >> $g_HFILE print "#define true 1" >> $g_HFILE print "#define TRUE 1" >> $g_HFILE print "#define false 0" >> $g_HFILE print "#define FALSE 0" >> $g_HFILE print "#define string char*" >> $g_HFILE print "#define STRING char*" >> $g_HFILE print "#define integer long" >> $g_HFILE print "#define INTEGER long" >> $g_HFILE print "#define floating double" >> $g_HFILE print "#define FLOATING double" >> $g_HFILE print >> $g_HFILE print "/* Peek and Poke */" >> $g_HFILE print "#include " >> $g_HFILE print "void __b2c__poke(char* x, long y){struct stat sb; if (stat(x, &sb) == -1 && errno == EFAULT) {" >> $g_HFILE print "fprintf(stderr, \"ERROR: Trying to access illegal memory with POKE at line %d!\\\\n\", __LINE__); exit(EXIT_FAILURE);}" >> $g_HFILE print "memset(x, y, sizeof(char));}" >> $g_HFILE print "#define poke(x, y) __b2c__poke((char*)x, y)" >> $g_HFILE print "#define POKE(x, y) __b2c__poke((char*)x, y)" >> $g_HFILE print "#define memory(x) (long)malloc(sizeof(char)*x);" >> $g_HFILE print "#define MEMORY(x) (long)malloc(sizeof(char)*x);" >> $g_HFILE print "long __b2c__peek(char* x) {struct stat sb; if (stat(x, &sb) == -1 && errno == EFAULT) {" >> $g_HFILE print "fprintf(stderr, \"ERROR: Trying to access illegal memory with PEEK at line %d!\\\\n\", __LINE__); exit(EXIT_FAILURE);} return(*x);}" >> $g_HFILE print "#define peek(x) __b2c__peek((char*)x)" >> $g_HFILE print "#define PEEK(x) __b2c__peek((char*)x)" >> $g_HFILE print >> $g_HFILE print "/* Declare reserved variable 'ARGUMENT' */" >> $g_HFILE print "int __b2c__counter;" >> $g_HFILE print "char ARGUMENT\$[$g_MAX_STRING];" >> $g_HFILE print "char argument\$[$g_MAX_STRING];" >> $g_HFILE print >> $g_HFILE print "/* Initialize stack arrays and pointer */" >> $g_HFILE print "char __b2c__stringstack[$g_STACK_DEPTH][$g_MAX_STRING];" >> $g_HFILE print "double __b2c__doublestack[$g_STACK_DEPTH];" >> $g_HFILE print "long __b2c__longstack[$g_STACK_DEPTH];" >> $g_HFILE print "int __b2c__typestack[$g_STACK_DEPTH];" >> $g_HFILE print "int __b2c__stackptr;" >> $g_HFILE print >> $g_HFILE print "/* User program definitions */" >> $g_HFILE # Initialize the arrayfiles print "char __b2c__stringarray[][$g_MAX_STRING] = {" > $STRINGARRAYFILE print "int __b2c__intarray[] = {" > $INTARRAYFILE print "double __b2c__floatarray[] = {" > $FLOATARRAYFILE # There are no imported symbols yet g_IMPORTED= # Start walking through program g_COUNTER=1 while read -r LINE do # Line is not empty? if [[ -n "$LINE" ]] then Parse_Line "$LINE" fi ((g_COUNTER+=1)) done < $SOURCEFILE # Finalize main C-file print "return 0;" >> $g_CFILE print "}" >> $g_CFILE # Finalize INT ARRAY file for DATA print " \"\" };" >> $STRINGARRAYFILE print >> $g_HFILE print "/* DATA definitions (string) */" >> $g_HFILE cat $STRINGARRAYFILE >> $g_HFILE rm $STRINGARRAYFILE print "int __b2c__stringarray_ptr = 0;" >> $g_HFILE # Finalize STRING ARRAY file for DATA print " 0};" >> $INTARRAYFILE print >> $g_HFILE print "/* DATA definitions (long) */" >> $g_HFILE cat $INTARRAYFILE >> $g_HFILE rm $INTARRAYFILE print "int __b2c__intarray_ptr = 0;" >> $g_HFILE # Finalize FLOAT ARRAY file for DATA print " 0.0};" >> $FLOATARRAYFILE print >> $g_HFILE print "/* DATA definitions (double) */" >> $g_HFILE cat $FLOATARRAYFILE >> $g_HFILE rm $FLOATARRAYFILE print "int __b2c__floatarray_ptr = 0;" >> $g_HFILE print "done." # Start indentation if [[ -n `which indent` ]] then print -n "Applying indentation... " indent $g_CFILE indent $g_HFILE rm *~ print "done." fi # Start compilation if [[ $g_NO_COMPILE -eq 0 ]] then print -n "Starting compilation... " $g_CCNAME -Wall $CCFLAGS -o ${SOURCEFILE%.*} $g_CFILE $g_LDFLAGS > ${SOURCEFILE%.*}.log 2>&1 if [[ -z `cat ${SOURCEFILE%.*}.log` ]] then print "done." print "Program '${SOURCEFILE%.*}' ready." else cat ${SOURCEFILE%.*}.log fi fi exit 0